├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── settings.gradle └── src └── main └── java └── org └── smart4j └── framework ├── FrameworkConstant.java ├── HelperLoader.java ├── InstanceFactory.java ├── aop ├── AopHelper.java ├── AspectProxy.java ├── annotation │ ├── Aspect.java │ └── AspectOrder.java └── proxy │ ├── Proxy.java │ ├── ProxyChain.java │ └── ProxyManager.java ├── core ├── ClassHelper.java ├── ClassScanner.java ├── ConfigHelper.java ├── bean │ └── BaseBean.java ├── fault │ └── InitializationError.java └── impl │ ├── DefaultClassScanner.java │ └── support │ ├── AnnotationClassTemplate.java │ ├── ClassTemplate.java │ └── SupperClassTemplate.java ├── dao ├── DataAccessor.java ├── DatabaseHelper.java ├── SqlHelper.java ├── bean │ └── Pager.java └── impl │ └── DefaultDataAccessor.java ├── ds ├── DataSourceFactory.java └── impl │ ├── AbstractDataSourceFactory.java │ └── DefaultDataSourceFactory.java ├── ioc ├── BeanHelper.java ├── IocHelper.java └── annotation │ ├── Bean.java │ ├── Impl.java │ └── Inject.java ├── mvc ├── ActionHelper.java ├── ContainerListener.java ├── DataContext.java ├── DispatcherServlet.java ├── Handler.java ├── HandlerExceptionResolver.java ├── HandlerInvoker.java ├── HandlerMapping.java ├── Requester.java ├── UploadHelper.java ├── ViewResolver.java ├── annotation │ ├── Action.java │ └── Request.java ├── bean │ ├── Multipart.java │ ├── Multiparts.java │ ├── Params.java │ ├── Result.java │ └── View.java ├── fault │ ├── AuthcException.java │ ├── AuthzException.java │ └── UploadException.java └── impl │ ├── DefaultHandlerExceptionResolver.java │ ├── DefaultHandlerInvoker.java │ ├── DefaultHandlerMapping.java │ └── DefaultViewResolver.java ├── orm ├── DataSet.java ├── EntityHelper.java └── annotation │ ├── Column.java │ ├── Entity.java │ └── Table.java ├── plugin ├── Plugin.java ├── PluginHelper.java ├── PluginProxy.java └── WebPlugin.java ├── test ├── OrderedRunner.java └── annotation │ └── TestOrder.java ├── tx ├── TransactionProxy.java └── annotation │ ├── Service.java │ └── Transaction.java └── util ├── ArrayUtil.java ├── CastUtil.java ├── ClassUtil.java ├── CodecUtil.java ├── CollectionUtil.java ├── DateUtil.java ├── FileUtil.java ├── JsonUtil.java ├── MapUtil.java ├── ObjectUtil.java ├── PropsUtil.java ├── StreamUtil.java ├── StringUtil.java └── WebUtil.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven # 2 | target/ 3 | 4 | # IDEA # 5 | .idea/ 6 | *.iml 7 | 8 | # Eclipse # 9 | .settings/ 10 | .classpath 11 | .project 12 | /gradlew.bat 13 | /.gradle 14 | /gradle 15 | /gradlew 16 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Smart Framework 2 | 3 | ## 简介 4 | 5 | ### 1. 它是一款轻量级 Java Web 框架 6 | 7 | - 内置 IOC、AOP、ORM、DAO、MVC 等特性 8 | - 基于 Servlet 3.0 规范 9 | - 使用 Java 注解取代 XML 配置 10 | 11 | ### 2. 它使应用充分做到“前后端分离” 12 | 13 | - 客户端可使用 HTML 或 JSP 作为视图模板 14 | - 服务端可发布 REST 服务(使用 REST 插件) 15 | - 客户端通过 AJAX 获取服务端数据并进行界面渲染 16 | 17 | ### 3. 它可提高应用程序的开发效率 18 | 19 | - 面向基于 Web 的中小规模的应用程序 20 | - 新手能在较短时间内入门 21 | - 核心具有良好的定制性且插件易于扩展 22 | 23 | ![架构](http://i.imgur.com/NrH99Zu.png) 24 | 25 | ## 入门 26 | 27 | ### 1. 创建一个 Maven Web 工程 28 | 29 | 整个工程的目录结构如下: 30 | 31 | ``` 32 | smart-sample/ 33 |   ┗ src/ 34 |     ┗ main/ 35 |       ┗ java/ 36 |       ┗ resources/ 37 |       ┗ webapp/ 38 |   ┗ pom.xml 39 | ``` 40 | 41 | 在 `java` 目录下,创建以下包名目录结构: 42 | 43 | ``` 44 | org/ 45 |   ┗ smart4j/ 46 |     ┗ sample/ 47 |       ┗ action/ 48 |       ┗ entity/ 49 |       ┗ service/ 50 | ``` 51 | 52 | 可见,基础包名为:org.smart4j.sample,下面的配置中会用到它。 53 | 54 | ### 2. 配置 Maven 依赖 55 | 56 | 编辑 `pom.xml` 文件,添加 `smart-framework` 依赖: 57 | 58 | ```xml 59 | 60 | org.smart4j 61 | smart-framework 62 | [版本号] 63 | 64 | ``` 65 | 66 | > 提示:需要指定具体的版本号。若使用相关 Smart 插件,则需分别配置。 67 | 68 | ### 3. 编写 Smart 配置 69 | 70 | 在 `resources` 目录下,创建一个名为 `smart.properties` 的文件,内容如下: 71 | 72 | ``` 73 | smart.framework.app.base_package=org.smart4j.sample 74 | smart.framework.app.home_page=/users 75 | 76 | smart.framework.jdbc.driver=com.mysql.jdbc.Driver 77 | smart.framework.jdbc.url=jdbc:mysql://localhost:3306/smart-sample 78 | smart.framework.jdbc.username=root 79 | smart.framework.jdbc.password=root 80 | ``` 81 | 82 | > 提示:需根据实际情况修改以上配置。 83 | 84 | ### 4. 编写 Entity 类 85 | 86 | ```java 87 | package org.smart4j.sample.entity; 88 | 89 | import org.smart4j.framework.orm.annotation.Entity; 90 | 91 | @Entity 92 | public class User { 93 | 94 | private long id; 95 | 96 | private String username; 97 | 98 | private String password; 99 | 100 | // getter/setter 101 | } 102 | ``` 103 | 104 | ### 5. 编写 Service 接口及其实现 105 | 106 | Service 接口 107 | 108 | ```java 109 | package org.smart4j.sample.service; 110 | 111 | import java.util.List; 112 | import java.util.Map; 113 | import org.smart4j.sample.entity.User; 114 | 115 | public interface UserService { 116 | 117 | List findUserList(); 118 | 119 | User findUser(long id); 120 | 121 | boolean saveUser(Map fieldMap); 122 | 123 | boolean updateUser(long id, Map fieldMap); 124 | 125 | boolean deleteUser(long id); 126 | } 127 | ``` 128 | 129 | Service 实现 130 | 131 | ```java 132 | package org.smart4j.sample.service.impl; 133 | 134 | import java.util.List; 135 | import java.util.Map; 136 | import org.smart4j.framework.orm.DataSet; 137 | import org.smart4j.framework.tx.annotation.Service; 138 | import org.smart4j.framework.tx.annotation.Transaction; 139 | import org.smart4j.sample.entity.User; 140 | import org.smart4j.sample.service.UserService; 141 | 142 | @Service 143 | public class UserServiceImpl implements UserService { 144 | 145 | @Override 146 | public List findUserList() { 147 | return DataSet.selectList(User.class); 148 | } 149 | 150 | @Override 151 | public User findUser(long id) { 152 | return DataSet.select(User.class, "id = ?", id); 153 | } 154 | 155 | @Override 156 | @Transaction 157 | public boolean saveUser(Map fieldMap) { 158 | return DataSet.insert(User.class, fieldMap); 159 | } 160 | 161 | @Override 162 | @Transaction 163 | public boolean updateUser(long id, Map fieldMap) { 164 | return DataSet.update(User.class, fieldMap, "id = ?", id); 165 | } 166 | 167 | @Override 168 | @Transaction 169 | public boolean deleteUser(long id) { 170 | return DataSet.delete(User.class, "id = ?", id); 171 | } 172 | } 173 | ``` 174 | 175 | ### 5. 编写 Action 类 176 | 177 | ```java 178 | package org.smart4j.sample.action; 179 | 180 | import java.util.List; 181 | import java.util.Map; 182 | import org.smart4j.framework.ioc.annotation.Inject; 183 | import org.smart4j.framework.mvc.DataContext; 184 | import org.smart4j.framework.mvc.annotation.Action; 185 | import org.smart4j.framework.mvc.annotation.Request; 186 | import org.smart4j.framework.mvc.bean.Params; 187 | import org.smart4j.framework.mvc.bean.Result; 188 | import org.smart4j.framework.mvc.bean.View; 189 | import org.smart4j.sample.entity.User; 190 | import org.smart4j.sample.service.UserService; 191 | 192 | @Action 193 | public class UserAction { 194 | 195 | @Inject 196 | private UserService userService; 197 | 198 | @Request.Get("/users") 199 | public View index() { 200 | List userList = userService.findUserList(); 201 | DataContext.Request.put("userList", userList); 202 | return new View("user.jsp"); 203 | } 204 | 205 | @Request.Get("/user") 206 | public View create() { 207 | return new View("user_create.jsp"); 208 | } 209 | 210 | @Request.Post("/user") 211 | public Result save(Params params) { 212 | Map fieldMap = params.getFieldMap(); 213 | boolean result = userService.saveUser(fieldMap); 214 | return new Result(result); 215 | } 216 | 217 | @Request.Get("/user/{id}") 218 | public View edit(long id) { 219 | User user = userService.findUser(id); 220 | DataContext.Request.put("user", user); 221 | return new View("user_edit.jsp"); 222 | } 223 | 224 | @Request.Put("/user/{id}") 225 | public Result update(long id, Params params) { 226 | Map fieldMap = params.getFieldMap(); 227 | boolean result = userService.updateUser(id, fieldMap); 228 | return new Result(result); 229 | } 230 | 231 | @Request.Delete("/user/{id}") 232 | public Result delete(long id) { 233 | boolean result = userService.deleteUser(id); 234 | return new Result(result); 235 | } 236 | } 237 | ``` 238 | 239 | ### 6. 编写视图 240 | 241 | 在 Action 中使用了 JSP 作为视图展现技术,需要编写以下 JSP 文件: 242 | 243 | - user.jsp 244 | - user_list.jsp 245 | - user_create.jsp 246 | - user_edit.jsp 247 | 248 | > 提示:更多相关细节,请参考 [Smart Sample](http://git.oschina.net/huangyong/smart-sample) 示例。 249 | 250 | ## 提高 251 | 252 | TODO 253 | 254 | ## 示例 255 | 256 | - Smart Sample:http://git.oschina.net/huangyong/smart-sample 257 | - Smart Bootstrap:http://git.oschina.net/huangyong/smart-bootstrap 258 | - Smart REST Server:http://git.oschina.net/huangyong/smart-rest-server 259 | - Smart REST Client:http://git.oschina.net/huangyong/smart-rest-client 260 | 261 | ## 附录 262 | 263 | ### 相关插件 264 | 265 | > 注意:插件依赖于框架,不能独立使用。 266 | 267 | - [smart-plugin-security](http://git.oschina.net/huangyong/smart-plugin-security) -- 基于 [Apache Shiro](http://shiro.apache.org/) 的安全控制插件 268 | - [smart-plugin-cache](http://git.oschina.net/huangyong/smart-plugin-cache) -- 基于注解的 Cache 插件 269 | - [smart-plugin-i18n](http://git.oschina.net/huangyong/smart-plugin-i18n) -- 通用的 I18N 插件 270 | - [smart-plugin-mail](http://git.oschina.net/huangyong/smart-plugin-mail) -- 基于 [Apache Commons Email](http://commons.apache.org/proper/commons-email/) 的邮件收发插件 271 | - [smart-plugin-template](http://git.oschina.net/huangyong/smart-plugin-template) -- 基于 [Apache Velocity](http://velocity.apache.org/) 的模板引擎插件 272 | - [smart-plugin-job](http://git.oschina.net/huangyong/smart-plugin-job) -- 基于 [Quartz](http://www.quartz-scheduler.org/) 的作业调度插件 273 | - [smart-plugin-soap](http://git.oschina.net/huangyong/smart-plugin-soap) -- 基于 [Apache CXF](http://cxf.apache.org/) 的 SOAP Web Service 插件 274 | - [smart-plugin-rest](http://git.oschina.net/huangyong/smart-plugin-rest) -- 基于 [Apache CXF](http://cxf.apache.org/) 的 REST Web Service 插件 275 | - [smart-plugin-hessian](http://git.oschina.net/huangyong/smart-plugin-hessian) -- 基于 [Hessian](http://hessian.caucho.com/) 的 RMI 插件 276 | - [smart-plugin-xmlrpc](http://git.oschina.net/huangyong/smart-plugin-xmlrpc) -- 基于 [Apache XML-RPC](http://ws.apache.org/xmlrpc/) 的 XML-RPC 插件 277 | - [smart-plugin-search](http://git.oschina.net/huangyong/smart-plugin-search) -- 基于 [Apache Lucene](http://lucene.apache.org/) 的搜索引擎插件 278 | - [smart-plugin-mybatis](http://git.oschina.net/free/smart-plugin-mybatis) -- 基于 [MyBatis](http://mybatis.github.io/mybatis-3/) 的数据持久层插件 279 | - [smart-plugin-args](http://git.oschina.net/free/smart-plugin-args) -- 强大的 Action 方法参数绑定的插件 280 | - [smart-plugin-c3p0](http://git.oschina.net/huangyong/smart-plugin-c3p0) -- 基于 [C3P0](http://sourceforge.net/projects/c3p0/) 的连接池插件 281 | - [smart-plugin-druid](http://git.oschina.net/huangyong/smart-plugin-druid) -- 基于 [Druid](https://github.com/alibaba/druid) 的连接池插件 282 | 283 | ### 相关模块 284 | 285 | > 注意:模块不依赖于框架,可以独立使用。 286 | 287 | - [smart-sso](http://git.oschina.net/huangyong/smart-sso) -- 基于 [Jasig CAS](http://www.jasig.org/cas) 的 SSO 模块 288 | - [smart-cache](http://git.oschina.net/huangyong/smart-cache) -- 通用的 Cache 模块与基于内存的实现 289 | - [smart-cache-ehcache](http://git.oschina.net/huangyong/smart-cache-ehcache) -- 基于 [EhCache](http://www.ehcache.org/) 的 Cache 模块 290 | - [smart-cache-redis](http://git.oschina.net/lujianing/smart-cache-redis) -- 基于 [Jedis](https://github.com/xetorthio/jedis/) 的 Cache 模块 291 | 292 | ### 参考资料 293 | 294 | - Smart 系列博文:http://my.oschina.net/huangyong/blog/158380 295 | - Maven 那点事儿:http://my.oschina.net/huangyong/blog/194583 -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'war' 2 | 3 | group = 'org.smart4j' 4 | version = '2.3.3-SNAPSHOT' 5 | 6 | description = """smart-framework""" 7 | 8 | sourceCompatibility = 1.6 9 | targetCompatibility = 1.6 10 | 11 | repositories { 12 | jcenter() 13 | } 14 | 15 | dependencies { 16 | compile 'org.slf4j:slf4j-log4j12:1.7.5', 17 | 'org.codehaus.jackson:jackson-mapper-asl:1.9.13', 18 | 'org.codehaus.jackson:jackson-jaxrs:1.9.13', 19 | 'cglib:cglib:2.2.2', 20 | 'commons-lang:commons-lang:2.4', 21 | 'commons-collections:commons-collections:3.2.1', 22 | 'commons-beanutils:commons-beanutils:1.8.3', 23 | 'commons-dbcp:commons-dbcp:1.4', 24 | 'commons-dbutils:commons-dbutils:1.5', 25 | 'commons-fileupload:commons-fileupload:1.3', 26 | 'commons-codec:commons-codec:1.8' 27 | testCompile 'junit:junit:4.11' 28 | providedCompile "javax.servlet:javax.servlet-api:3.0.1" 29 | 30 | } 31 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'smart-framework' 2 | -------------------------------------------------------------------------------- /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 | } 21 | -------------------------------------------------------------------------------- /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 | public final class HelperLoader { 19 | 20 | public static void init() { 21 | // 定义需要加载的 Helper 类 22 | Class[] classList = { 23 | DatabaseHelper.class, 24 | EntityHelper.class, 25 | ActionHelper.class, 26 | BeanHelper.class, 27 | AopHelper.class, 28 | IocHelper.class, 29 | PluginHelper.class, 30 | }; 31 | // 按照顺序加载类 32 | for (Class cls : classList) { 33 | ClassUtil.loadClass(cls.getName()); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /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 cache = new ConcurrentHashMap(); 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 getInstance(String cacheKey, Class 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 | } 142 | -------------------------------------------------------------------------------- /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, List>> proxyMap = createProxyMap(); 45 | // 创建 Target Map(用于 存放目标类 与 代理类列表 的映射关系) 46 | Map, List> targetMap = createTargetMap(proxyMap); 47 | // 遍历 Target Map 48 | for (Map.Entry, List> targetEntry : targetMap.entrySet()) { 49 | // 分别获取 map 中的 key 与 value 50 | Class targetClass = targetEntry.getKey(); 51 | List 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, List>> createProxyMap() throws Exception { 63 | Map, List>> proxyMap = new LinkedHashMap, List>>(); 64 | // 添加相关代理 65 | addPluginProxy(proxyMap); // 插件代理 66 | addAspectProxy(proxyMap); // 切面代理 67 | addTransactionProxy(proxyMap); // 事务代理 68 | return proxyMap; 69 | } 70 | 71 | private static void addPluginProxy(Map, List>> proxyMap) throws Exception { 72 | // 获取插件包名下父类为 PluginProxy 的所有类(插件代理类) 73 | List> 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, List>> proxyMap) throws Exception { 86 | // 获取切面类(所有继承于 BaseAspect 的类) 87 | List> 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> targetClassList = createTargetClassList(aspect); 100 | // 初始化 Proxy Map 101 | proxyMap.put(aspectProxyClass, targetClassList); 102 | } 103 | } 104 | } 105 | 106 | private static void addTransactionProxy(Map, List>> proxyMap) { 107 | // 使用 TransactionProxy 代理所有 Service 类 108 | List> serviceClassList = ClassHelper.getClassListByAnnotation(Service.class); 109 | proxyMap.put(TransactionProxy.class, serviceClassList); 110 | } 111 | 112 | private static void sortAspectProxyClassList(List> proxyClassList) { 113 | // 排序代理类列表 114 | Collections.sort(proxyClassList, new Comparator>() { 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> createTargetClassList(Aspect aspect) throws Exception { 137 | List> targetClassList = new ArrayList>(); 138 | // 获取 Aspect 注解的相关属性 139 | String pkg = aspect.pkg(); 140 | String cls = aspect.cls(); 141 | Class 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, List> createTargetMap(Map, List>> proxyMap) throws Exception { 166 | Map, List> targetMap = new HashMap, List>(); 167 | // 遍历 Proxy Map 168 | for (Map.Entry, List>> proxyEntry : proxyMap.entrySet()) { 169 | // 分别获取 map 中的 key 与 value 170 | Class proxyClass = proxyEntry.getKey(); 171 | List> 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 baseAspectList = new ArrayList(); 181 | baseAspectList.add(baseAspect); 182 | targetMap.put(targetClass, baseAspectList); 183 | } 184 | } 185 | } 186 | return targetMap; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /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 | } 66 | -------------------------------------------------------------------------------- /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 annotation() default Aspect.class; 35 | } 36 | -------------------------------------------------------------------------------- /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 | } 20 | -------------------------------------------------------------------------------- /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 | } 20 | -------------------------------------------------------------------------------- /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 proxyList = new ArrayList(); 23 | private int proxyIndex = 0; 24 | 25 | public ProxyChain(Class targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List 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 | } 56 | -------------------------------------------------------------------------------- /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 createProxy(final Class targetClass, final List 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 | } 27 | -------------------------------------------------------------------------------- /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> getClassList() { 29 | return classScanner.getClassList(basePackage); 30 | } 31 | 32 | /** 33 | * 获取基础包名中指定父类或接口的相关类 34 | */ 35 | public static List> getClassListBySuper(Class superClass) { 36 | return classScanner.getClassListBySuper(basePackage, superClass); 37 | } 38 | 39 | /** 40 | * 获取基础包名中指定注解的相关类 41 | */ 42 | public static List> getClassListByAnnotation(Class annotationClass) { 43 | return classScanner.getClassListByAnnotation(basePackage, annotationClass); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /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> getClassList(String packageName); 18 | 19 | /** 20 | * 获取指定包名中指定注解的相关类 21 | */ 22 | List> getClassListByAnnotation(String packageName, Class annotationClass); 23 | 24 | /** 25 | * 获取指定包名中指定父类或接口的相关类 26 | */ 27 | List> getClassListBySuper(String packageName, Class superClass); 28 | } 29 | -------------------------------------------------------------------------------- /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 getMap(String prefix) { 69 | return PropsUtil.getMap(configProps, prefix); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /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 | } 32 | -------------------------------------------------------------------------------- /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 | } 27 | -------------------------------------------------------------------------------- /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> 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> getClassListByAnnotation(String packageName, Class 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> 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 | } 50 | -------------------------------------------------------------------------------- /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 annotationClass; 14 | 15 | protected AnnotationClassTemplate(String packageName, Class annotationClass) { 16 | super(packageName); 17 | this.annotationClass = annotationClass; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /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> getClassList() { 34 | List> classList = new ArrayList>(); 35 | try { 36 | // 从包名获取 URL 类型的资源 37 | Enumeration 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 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> 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> 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 | } -------------------------------------------------------------------------------- /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 | } 18 | -------------------------------------------------------------------------------- /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 queryEntity(Class entityClass, String sql, Object... params); 19 | 20 | /** 21 | * 查询对应的实体列表,返回多条记录 22 | */ 23 | List queryEntityList(Class entityClass, String sql, Object... params); 24 | 25 | /** 26 | * 查询对应的实体列表,返回单条记录(主键 => 实体) 27 | */ 28 | Map queryEntityMap(Class entityClass, String sql, Object... params); 29 | 30 | /** 31 | * 查询对应的数据,返回单条记录 32 | */ 33 | Object[] queryArray(String sql, Object... params); 34 | 35 | /** 36 | * 查询对应的数据,返回多条记录 37 | */ 38 | List queryArrayList(String sql, Object... params); 39 | 40 | /** 41 | * 查询对应的数据,返回单条记录(列名 => 数据) 42 | */ 43 | Map queryMap(String sql, Object... params); 44 | 45 | /** 46 | * 查询对应的数据,返回多条记录(列名 => 数据) 47 | */ 48 | List> queryMapList(String sql, Object... params); 49 | 50 | /** 51 | * 查询对应的数据,返回单条数据(列名 => 数据) 52 | */ 53 | T queryColumn(String sql, Object... params); 54 | 55 | /** 56 | * 查询对应的数据,返回多条数据(列名 => 数据) 57 | */ 58 | List queryColumnList(String sql, Object... params); 59 | 60 | /** 61 | * 查询指定列名对应的数据,返回多条数据(列名对应的数据 => 列名与数据的映射关系) 62 | */ 63 | Map> 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 | } 80 | -------------------------------------------------------------------------------- /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 connContainer = new ThreadLocal(); 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 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 queryEntity(Class entityClass, String sql, Object... params) { 158 | return dataAccessor.queryEntity(entityClass, sql, params); 159 | } 160 | 161 | /** 162 | * 根据 SQL 语句查询 Entity 列表 163 | */ 164 | public static List queryEntityList(Class 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 Map queryEntityMap(Class 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 queryArrayList(String sql, Object... params) { 186 | return dataAccessor.queryArrayList(sql, params); 187 | } 188 | 189 | /** 190 | * 根据 SQL 语句查询 Map 格式的字段(单条记录) 191 | */ 192 | public static Map queryMap(String sql, Object... params) { 193 | return dataAccessor.queryMap(sql, params); 194 | } 195 | 196 | /** 197 | * 根据 SQL 语句查询 Map 格式的字段列表(多条记录) 198 | */ 199 | public static List> queryMapList(String sql, Object... params) { 200 | return dataAccessor.queryMapList(sql, params); 201 | } 202 | 203 | /** 204 | * 根据 SQL 语句查询指定字段(单条记录) 205 | */ 206 | public static T queryColumn(String sql, Object... params) { 207 | return dataAccessor.queryColumn(sql, params); 208 | } 209 | 210 | /** 211 | * 根据 SQL 语句查询指定字段列表(多条记录) 212 | */ 213 | public static List queryColumnList(String sql, Object... params) { 214 | return dataAccessor.queryColumnList(sql, params); 215 | } 216 | 217 | /** 218 | * 根据 SQL 语句查询指定字段映射(多条记录) 219 | */ 220 | public static Map> 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 | } 245 | -------------------------------------------------------------------------------- /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 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 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 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 | } 203 | -------------------------------------------------------------------------------- /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 extends BaseBean { 13 | 14 | private int pageNumber; // 页面编号 15 | private int pageSize; // 每页条数 16 | private long totalRecord; // 总记录数 17 | private long totalPage; // 总页面数 18 | private List recordList; // 数据列表 19 | 20 | public Pager() { 21 | } 22 | 23 | public Pager(int pageNumber, int pageSize, long totalRecord, List recordList) { 24 | this.pageNumber = pageNumber; 25 | this.pageSize = pageSize; 26 | this.totalRecord = totalRecord; 27 | this.recordList = recordList; 28 | if (pageSize != 0) { 29 | totalPage = totalRecord % pageSize == 0 ? totalRecord / pageSize : totalRecord / pageSize + 1; 30 | } 31 | } 32 | 33 | public int getPageNumber() { 34 | return pageNumber; 35 | } 36 | 37 | public int getPageSize() { 38 | return pageSize; 39 | } 40 | 41 | public long getTotalRecord() { 42 | return totalRecord; 43 | } 44 | 45 | public long getTotalPage() { 46 | return totalPage; 47 | } 48 | 49 | public List getRecordList() { 50 | return recordList; 51 | } 52 | 53 | // ---------------------------------------------------------------------------------------------------- 54 | 55 | public boolean isFirstPage() { 56 | return pageNumber == 1; 57 | } 58 | 59 | public boolean isLastPage() { 60 | return pageNumber == totalPage; 61 | } 62 | 63 | public boolean isPrevPage() { 64 | return pageNumber > 1 && pageNumber <= totalPage; 65 | } 66 | 67 | public boolean isNextPage() { 68 | return pageNumber < totalPage; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /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 | import javax.sql.DataSource; 11 | import org.apache.commons.dbutils.BasicRowProcessor; 12 | import org.apache.commons.dbutils.BeanProcessor; 13 | import org.apache.commons.dbutils.QueryRunner; 14 | import org.apache.commons.dbutils.handlers.ArrayHandler; 15 | import org.apache.commons.dbutils.handlers.ArrayListHandler; 16 | import org.apache.commons.dbutils.handlers.BeanHandler; 17 | import org.apache.commons.dbutils.handlers.BeanListHandler; 18 | import org.apache.commons.dbutils.handlers.BeanMapHandler; 19 | import org.apache.commons.dbutils.handlers.ColumnListHandler; 20 | import org.apache.commons.dbutils.handlers.KeyedHandler; 21 | import org.apache.commons.dbutils.handlers.MapHandler; 22 | import org.apache.commons.dbutils.handlers.MapListHandler; 23 | import org.apache.commons.dbutils.handlers.ScalarHandler; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | import org.smart4j.framework.dao.DataAccessor; 27 | import org.smart4j.framework.dao.DatabaseHelper; 28 | import org.smart4j.framework.orm.EntityHelper; 29 | import org.smart4j.framework.util.ArrayUtil; 30 | import org.smart4j.framework.util.MapUtil; 31 | 32 | /** 33 | * 默认数据访问器 34 | *
35 | * 基于 Apache Commons DbUtils 实现 36 | * 37 | * @author huangyong 38 | * @since 2.3 39 | */ 40 | public class DefaultDataAccessor implements DataAccessor { 41 | 42 | private static final Logger logger = LoggerFactory.getLogger(DefaultDataAccessor.class); 43 | 44 | private final QueryRunner queryRunner; 45 | 46 | public DefaultDataAccessor() { 47 | DataSource dataSource = DatabaseHelper.getDataSource(); 48 | queryRunner = new QueryRunner(dataSource); 49 | } 50 | 51 | @Override 52 | public T queryEntity(Class entityClass, String sql, Object... params) { 53 | T result; 54 | try { 55 | Map columnMap = EntityHelper.getColumnMap(entityClass); 56 | if (MapUtil.isNotEmpty(columnMap)) { 57 | result = queryRunner.query(sql, new BeanHandler(entityClass, new BasicRowProcessor(new BeanProcessor(columnMap))), params); 58 | } else { 59 | result = queryRunner.query(sql, new BeanHandler(entityClass), params); 60 | } 61 | } catch (SQLException e) { 62 | logger.error("查询出错!", e); 63 | throw new RuntimeException(e); 64 | } 65 | printSQL(sql); 66 | return result; 67 | } 68 | 69 | @Override 70 | public List queryEntityList(Class entityClass, String sql, Object... params) { 71 | List result; 72 | try { 73 | Map columnMap = EntityHelper.getColumnMap(entityClass); 74 | if (MapUtil.isNotEmpty(columnMap)) { 75 | result = queryRunner.query(sql, new BeanListHandler(entityClass, new BasicRowProcessor(new BeanProcessor(columnMap))), params); 76 | } else { 77 | result = queryRunner.query(sql, new BeanListHandler(entityClass), params); 78 | } 79 | } catch (SQLException e) { 80 | logger.error("查询出错!", e); 81 | throw new RuntimeException(e); 82 | } 83 | printSQL(sql); 84 | return result; 85 | } 86 | 87 | @Override 88 | public Map queryEntityMap(Class entityClass, String sql, Object... params) { 89 | Map entityMap; 90 | try { 91 | entityMap = queryRunner.query(sql, new BeanMapHandler(entityClass), params); 92 | } catch (SQLException e) { 93 | logger.error("查询出错!", e); 94 | throw new RuntimeException(e); 95 | } 96 | printSQL(sql); 97 | return entityMap; 98 | } 99 | 100 | @Override 101 | public Object[] queryArray(String sql, Object... params) { 102 | Object[] array; 103 | try { 104 | array = queryRunner.query(sql, new ArrayHandler(), params); 105 | } catch (SQLException e) { 106 | logger.error("查询出错!", e); 107 | throw new RuntimeException(e); 108 | } 109 | printSQL(sql); 110 | return array; 111 | } 112 | 113 | @Override 114 | public List queryArrayList(String sql, Object... params) { 115 | List arrayList; 116 | try { 117 | arrayList = queryRunner.query(sql, new ArrayListHandler(), params); 118 | } catch (SQLException e) { 119 | logger.error("查询出错!", e); 120 | throw new RuntimeException(e); 121 | } 122 | printSQL(sql); 123 | return arrayList; 124 | } 125 | 126 | @Override 127 | public Map queryMap(String sql, Object... params) { 128 | Map map; 129 | try { 130 | map = queryRunner.query(sql, new MapHandler(), params); 131 | } catch (SQLException e) { 132 | logger.error("查询出错!", e); 133 | throw new RuntimeException(e); 134 | } 135 | printSQL(sql); 136 | return map; 137 | } 138 | 139 | @Override 140 | public List> queryMapList(String sql, Object... params) { 141 | List> fieldMapList; 142 | try { 143 | fieldMapList = queryRunner.query(sql, new MapListHandler(), params); 144 | } catch (SQLException e) { 145 | logger.error("查询出错!", e); 146 | throw new RuntimeException(e); 147 | } 148 | printSQL(sql); 149 | return fieldMapList; 150 | } 151 | 152 | @Override 153 | public T queryColumn(String sql, Object... params) { 154 | T obj; 155 | try { 156 | obj = queryRunner.query(sql, new ScalarHandler(), params); 157 | } catch (SQLException e) { 158 | logger.error("查询出错!", e); 159 | throw new RuntimeException(e); 160 | } 161 | printSQL(sql); 162 | return obj; 163 | } 164 | 165 | @Override 166 | public List queryColumnList(String sql, Object... params) { 167 | List list; 168 | try { 169 | list = queryRunner.query(sql, new ColumnListHandler(), params); 170 | } catch (SQLException e) { 171 | logger.error("查询出错!", e); 172 | throw new RuntimeException(e); 173 | } 174 | printSQL(sql); 175 | return list; 176 | } 177 | 178 | @Override 179 | public Map> queryColumnMap(String column, String sql, Object... params) { 180 | Map> map; 181 | try { 182 | map = queryRunner.query(sql, new KeyedHandler(column), params); 183 | } catch (SQLException e) { 184 | logger.error("查询出错!", e); 185 | throw new RuntimeException(e); 186 | } 187 | printSQL(sql); 188 | return map; 189 | } 190 | 191 | @Override 192 | public long queryCount(String sql, Object... params) { 193 | long result; 194 | try { 195 | result = queryRunner.query(sql, new ScalarHandler("count(*)"), params); 196 | } catch (SQLException e) { 197 | logger.error("查询出错!", e); 198 | throw new RuntimeException(e); 199 | } 200 | printSQL(sql); 201 | return result; 202 | } 203 | 204 | @Override 205 | public int update(String sql, Object... params) { 206 | int result; 207 | try { 208 | Connection conn = DatabaseHelper.getConnection(); 209 | result = queryRunner.update(conn, sql, params); 210 | } catch (SQLException e) { 211 | logger.error("更新出错!", e); 212 | throw new RuntimeException(e); 213 | } 214 | printSQL(sql); 215 | return result; 216 | } 217 | 218 | @Override 219 | public Serializable insertReturnPK(String sql, Object... params) { 220 | Serializable key = null; 221 | try { 222 | Connection conn = DatabaseHelper.getConnection(); 223 | PreparedStatement pstmt = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); 224 | if (ArrayUtil.isNotEmpty(params)) { 225 | for (int i = 0; i < params.length; i++) { 226 | pstmt.setObject(i + 1, params[i]); 227 | } 228 | } 229 | int rows = pstmt.executeUpdate(); 230 | if (rows == 1) { 231 | ResultSet rs = pstmt.getGeneratedKeys(); 232 | if (rs.next()) { 233 | key = (Serializable) rs.getObject(1); 234 | } 235 | } 236 | } catch (SQLException e) { 237 | logger.error("插入出错!", e); 238 | throw new RuntimeException(e); 239 | } 240 | printSQL(sql); 241 | return key; 242 | } 243 | 244 | private static void printSQL(String sql) { 245 | logger.debug("[Smart] SQL - {}", sql); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /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 | } 20 | -------------------------------------------------------------------------------- /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 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 | } 46 | -------------------------------------------------------------------------------- /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 | * 默认数据源工厂 7 | *
8 | * 基于 Apache Commons DBCP 实现 9 | * 10 | * @author huangyong 11 | * @since 2.3 12 | */ 13 | public class DefaultDataSourceFactory extends AbstractDataSourceFactory { 14 | 15 | @Override 16 | public BasicDataSource createDataSource() { 17 | return new BasicDataSource(); 18 | } 19 | 20 | @Override 21 | public void setDriver(BasicDataSource ds, String driver) { 22 | ds.setDriverClassName(driver); 23 | } 24 | 25 | @Override 26 | public void setUrl(BasicDataSource ds, String url) { 27 | ds.setUrl(url); 28 | } 29 | 30 | @Override 31 | public void setUsername(BasicDataSource ds, String username) { 32 | ds.setUsername(username); 33 | } 34 | 35 | @Override 36 | public void setPassword(BasicDataSource ds, String password) { 37 | ds.setPassword(password); 38 | } 39 | 40 | @Override 41 | public void setAdvancedConfig(BasicDataSource ds) { 42 | // 解决 java.sql.SQLException: Already closed. 的问题(连接池会自动关闭长时间没有使用的连接) 43 | ds.setValidationQuery("select 1 from dual"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /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, Object> beanMap = new HashMap, Object>(); 25 | 26 | static { 27 | try { 28 | // 获取应用包路径下所有的类 29 | List> 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, Object> getBeanMap() { 51 | return beanMap; 52 | } 53 | 54 | /** 55 | * 获取 Bean 实例 56 | */ 57 | @SuppressWarnings("unchecked") 58 | public static T getBean(Class 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 | } 72 | -------------------------------------------------------------------------------- /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, Object> beanMap = BeanHelper.getBeanMap(); 25 | for (Map.Entry, 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> implementClassList = ClassHelper.getClassListBySuper(interfaceClass); 73 | if (CollectionUtil.isNotEmpty(implementClassList)) { 74 | // 获取第一个实现类 75 | implementClass = implementClassList.get(0); 76 | } 77 | } 78 | // 返回实现类对象 79 | return implementClass; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /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 | } 18 | -------------------------------------------------------------------------------- /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 | } 20 | -------------------------------------------------------------------------------- /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 | } 18 | -------------------------------------------------------------------------------- /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 actionMap = new LinkedHashMap(); 27 | 28 | static { 29 | // 获取所有 Action 类 30 | List> actionClassList = ClassHelper.getClassListByAnnotation(Action.class); 31 | if (CollectionUtil.isNotEmpty(actionClassList)) { 32 | // 定义两个 Action Map 33 | Map commonActionMap = new HashMap(); // 存放普通 Action Map 34 | Map regexpActionMap = new HashMap(); // 存放带有正则表达式的 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 commonActionMap, Map 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 commonActionMap, Map 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 getActionMap() { 86 | return actionMap; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /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 | * @author huangyong 20 | * @since 1.0 21 | */ 22 | @WebListener 23 | public class ContainerListener implements ServletContextListener { 24 | 25 | /** 26 | * 当容器初始化时调用 27 | */ 28 | @Override 29 | public void contextInitialized(ServletContextEvent sce) { 30 | // 获取 ServletContext 31 | ServletContext servletContext = sce.getServletContext(); 32 | // 初始化相关 Helper 类 33 | HelperLoader.init(); 34 | // 添加 Servlet 映射 35 | addServletMapping(servletContext); 36 | // 注册 WebPlugin 37 | registerWebPlugin(servletContext); 38 | } 39 | 40 | /** 41 | * 当容器销毁时调用 42 | */ 43 | @Override 44 | public void contextDestroyed(ServletContextEvent sce) { 45 | // 销毁插件 46 | destroyPlugin(); 47 | } 48 | 49 | private void addServletMapping(ServletContext context) { 50 | // 用 DefaultServlet 映射所有静态资源 51 | registerDefaultServlet(context); 52 | // 用 JspServlet 映射所有 JSP 请求 53 | registerJspServlet(context); 54 | } 55 | 56 | private void registerDefaultServlet(ServletContext context) { 57 | ServletRegistration defaultServlet = context.getServletRegistration("default"); 58 | defaultServlet.addMapping("/index.html"); 59 | defaultServlet.addMapping("/favicon.ico"); 60 | String wwwPath = FrameworkConstant.WWW_PATH; 61 | if (StringUtil.isNotEmpty(wwwPath)) { 62 | defaultServlet.addMapping(wwwPath + "*"); 63 | } 64 | } 65 | 66 | private void registerJspServlet(ServletContext context) { 67 | ServletRegistration jspServlet = context.getServletRegistration("jsp"); 68 | jspServlet.addMapping("/index.jsp"); 69 | String jspPath = FrameworkConstant.JSP_PATH; 70 | if (StringUtil.isNotEmpty(jspPath)) { 71 | jspServlet.addMapping(jspPath + "*"); 72 | } 73 | } 74 | 75 | private void registerWebPlugin(ServletContext servletContext) { 76 | List pluginList = PluginHelper.getPluginList(); 77 | for (Plugin plugin : pluginList) { 78 | if (plugin instanceof WebPlugin) { 79 | WebPlugin webPlugin = (WebPlugin) plugin; 80 | webPlugin.register(servletContext); 81 | } 82 | } 83 | } 84 | 85 | private void destroyPlugin() { 86 | List pluginList = PluginHelper.getPluginList(); 87 | for (Plugin plugin : pluginList) { 88 | plugin.destroy(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /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 dataContextContainer = new ThreadLocal(); 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 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 getAll() { 112 | Map map = new HashMap(); 113 | Enumeration 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 get(String key) { 139 | return (T) getResponse().getHeader(key); 140 | } 141 | 142 | /** 143 | * 从 Response 中获取所有数据 144 | */ 145 | public static Map getAll() { 146 | Map map = new HashMap(); 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 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 getAll() { 185 | Map map = new HashMap(); 186 | Enumeration 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 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 getAll() { 238 | Map map = new HashMap(); 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 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 getAll() { 280 | Map map = new HashMap(); 281 | Enumeration 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 | } 290 | -------------------------------------------------------------------------------- /src/main/java/org/smart4j/framework/mvc/DispatcherServlet.java: -------------------------------------------------------------------------------- 1 | package org.smart4j.framework.mvc; 2 | 3 | import java.io.IOException; 4 | import javax.servlet.ServletConfig; 5 | import javax.servlet.ServletContext; 6 | import javax.servlet.ServletException; 7 | import javax.servlet.annotation.WebServlet; 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.smart4j.framework.FrameworkConstant; 14 | import org.smart4j.framework.InstanceFactory; 15 | import org.smart4j.framework.util.WebUtil; 16 | 17 | /** 18 | * 前端控制器 19 | * 20 | * @author huangyong 21 | * @since 1.0 22 | */ 23 | @WebServlet(urlPatterns = "/*", loadOnStartup = 0) 24 | public class DispatcherServlet extends HttpServlet { 25 | 26 | private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class); 27 | 28 | private HandlerMapping handlerMapping = InstanceFactory.getHandlerMapping(); 29 | private HandlerInvoker handlerInvoker = InstanceFactory.getHandlerInvoker(); 30 | private HandlerExceptionResolver handlerExceptionResolver = InstanceFactory.getHandlerExceptionResolver(); 31 | 32 | @Override 33 | public void init(ServletConfig config) throws ServletException { 34 | // 初始化相关配置 35 | ServletContext servletContext = config.getServletContext(); 36 | UploadHelper.init(servletContext); 37 | } 38 | 39 | @Override 40 | public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 41 | // 设置请求编码方式 42 | request.setCharacterEncoding(FrameworkConstant.UTF_8); 43 | // 获取当前请求相关数据 44 | String currentRequestMethod = request.getMethod(); 45 | String currentRequestPath = WebUtil.getRequestPath(request); 46 | logger.debug("[Smart] {}:{}", currentRequestMethod, currentRequestPath); 47 | // 将“/”请求重定向到首页 48 | if (currentRequestPath.equals("/")) { 49 | WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response); 50 | return; 51 | } 52 | // 去掉当前请求路径末尾的“/” 53 | if (currentRequestPath.endsWith("/")) { 54 | currentRequestPath = currentRequestPath.substring(0, currentRequestPath.length() - 1); 55 | } 56 | // 获取 Handler 57 | Handler handler = handlerMapping.getHandler(currentRequestMethod, currentRequestPath); 58 | // 若未找到 Action,则跳转到 404 页面 59 | if (handler == null) { 60 | WebUtil.sendError(HttpServletResponse.SC_NOT_FOUND, "", response); 61 | return; 62 | } 63 | // 初始化 DataContext 64 | DataContext.init(request, response); 65 | try { 66 | // 调用 Handler 67 | handlerInvoker.invokeHandler(request, response, handler); 68 | } catch (Exception e) { 69 | // 处理 Action 异常 70 | handlerExceptionResolver.resolveHandlerException(request, response, e); 71 | } finally { 72 | // 销毁 DataContext 73 | DataContext.destroy(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | } 23 | -------------------------------------------------------------------------------- /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 | } 24 | -------------------------------------------------------------------------------- /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 | } 20 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | // 设置上传限制 54 | int uploadLimit = FrameworkConstant.UPLOAD_LIMIT; 55 | if (uploadLimit != 0) { 56 | fileUpload.setFileSizeMax(uploadLimit * 1024 * 1024); // 单位为 M 57 | } 58 | } 59 | 60 | /** 61 | * 判断请求是否为 multipart 类型 62 | */ 63 | public static boolean isMultipart(HttpServletRequest request) { 64 | // 判断上传文件的内容是否为 multipart 类型 65 | return ServletFileUpload.isMultipartContent(request); 66 | } 67 | 68 | /** 69 | * 创建 multipart 请求参数列表 70 | */ 71 | public static List createMultipartParamList(HttpServletRequest request) throws Exception { 72 | // 定义参数列表 73 | List paramList = new ArrayList(); 74 | // 创建两个对象,分别对应 普通字段 与 文件字段 75 | Map fieldMap = new HashMap(); 76 | List multipartList = new ArrayList(); 77 | // 获取并遍历表单项 78 | List fileItemList; 79 | try { 80 | fileItemList = fileUpload.parseRequest(request); 81 | } catch (FileUploadBase.FileSizeLimitExceededException e) { 82 | // 异常转换(抛出自定义异常) 83 | throw new UploadException(e); 84 | } 85 | for (FileItem fileItem : fileItemList) { 86 | // 分两种情况处理表单项 87 | String fieldName = fileItem.getFieldName(); 88 | if (fileItem.isFormField()) { 89 | // 处理普通字段 90 | String fieldValue = fileItem.getString(FrameworkConstant.UTF_8); 91 | fieldMap.put(fieldName, fieldValue); 92 | } else { 93 | // 处理文件字段 94 | String fileName = FileUtil.getRealFileName(fileItem.getName()); 95 | if (StringUtil.isNotEmpty(fileName)) { 96 | long fileSize = fileItem.getSize(); 97 | String contentType = fileItem.getContentType(); 98 | InputStream inputSteam = fileItem.getInputStream(); 99 | // 创建 Multipart 对象,并将其添加到 multipartList 中 100 | Multipart multipart = new Multipart(fieldName, fileName, fileSize, contentType, inputSteam); 101 | multipartList.add(multipart); 102 | } 103 | } 104 | } 105 | // 初始化参数列表 106 | paramList.add(new Params(fieldMap)); 107 | paramList.add(new Multiparts(multipartList)); 108 | // 返回参数列表 109 | return paramList; 110 | } 111 | 112 | /** 113 | * 上传文件 114 | */ 115 | public static void uploadFile(String basePath, Multipart multipart) { 116 | try { 117 | if (multipart != null) { 118 | // 创建文件路径(绝对路径) 119 | String filePath = basePath + multipart.getFileName(); 120 | FileUtil.createFile(filePath); 121 | // 执行流复制操作 122 | InputStream inputStream = new BufferedInputStream(multipart.getInputStream()); 123 | OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(filePath)); 124 | StreamUtil.copyStream(inputStream, outputStream); 125 | } 126 | } catch (Exception e) { 127 | logger.error("上传文件出错!", e); 128 | throw new RuntimeException(e); 129 | } 130 | } 131 | 132 | /** 133 | * 批量上传文件 134 | */ 135 | public static void uploadFiles(String basePath, Multiparts multiparts) { 136 | for (Multipart multipart : multiparts.getAll()) { 137 | uploadFile(basePath, multipart); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /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 | } 23 | -------------------------------------------------------------------------------- /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 | } 18 | -------------------------------------------------------------------------------- /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 | } 70 | -------------------------------------------------------------------------------- /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 | } 48 | -------------------------------------------------------------------------------- /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 multipartList = new ArrayList(); 16 | 17 | public Multiparts(List multipartList) { 18 | this.multipartList = multipartList; 19 | } 20 | 21 | public int size() { 22 | return multipartList.size(); 23 | } 24 | 25 | public List getAll() { 26 | return multipartList; 27 | } 28 | 29 | public Multipart getOne() { 30 | return size() == 1 ? multipartList.get(0) : null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /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 fieldMap; 16 | 17 | public Params(Map fieldMap) { 18 | this.fieldMap = fieldMap; 19 | } 20 | 21 | public Map 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 | } 45 | -------------------------------------------------------------------------------- /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 | } 55 | -------------------------------------------------------------------------------- /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 data; // 相关数据 17 | 18 | public View(String path) { 19 | this.path = path; 20 | data = new HashMap(); 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 getData() { 41 | return data; 42 | } 43 | 44 | public void setData(Map data) { 45 | this.data = data; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /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 | } 27 | -------------------------------------------------------------------------------- /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 | } 27 | -------------------------------------------------------------------------------- /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 | } 27 | -------------------------------------------------------------------------------- /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 | Throwable cause = e.getCause(); 27 | if (cause == null) { 28 | logger.error(e.getMessage(), e); 29 | return; 30 | } 31 | if (cause instanceof AuthcException) { 32 | // 分两种情况进行处理 33 | if (WebUtil.isAJAX(request)) { 34 | // 跳转到 403 页面 35 | WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response); 36 | } else { 37 | // 重定向到首页 38 | WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response); 39 | } 40 | } else if (cause instanceof AuthzException) { 41 | // 跳转到 403 页面 42 | WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response); 43 | } else { 44 | // 跳转到 500 页面 45 | WebUtil.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, cause.getMessage(), response); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /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 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 createActionMethodParamList(HttpServletRequest request, Handler handler) throws Exception { 51 | // 定义参数列表 52 | List paramList = new ArrayList(); 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 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 createPathParamList(Matcher requestPathMatcher, Class[] actionParamTypes) { 73 | // 定义参数列表 74 | List paramList = new ArrayList(); 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 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 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 | } 110 | -------------------------------------------------------------------------------- /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 | * 默认处理器映射 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 actionMap = ActionHelper.getActionMap(); 25 | for (Map.Entry 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 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/smart4j/framework/mvc/impl/DefaultViewResolver.java: -------------------------------------------------------------------------------- 1 | package org.smart4j.framework.mvc.impl; 2 | 3 | import java.util.Map; 4 | import javax.servlet.http.HttpServletRequest; 5 | import javax.servlet.http.HttpServletResponse; 6 | import org.smart4j.framework.FrameworkConstant; 7 | import org.smart4j.framework.mvc.UploadHelper; 8 | import org.smart4j.framework.mvc.ViewResolver; 9 | import org.smart4j.framework.mvc.bean.Result; 10 | import org.smart4j.framework.mvc.bean.View; 11 | import org.smart4j.framework.util.MapUtil; 12 | import org.smart4j.framework.util.WebUtil; 13 | 14 | /** 15 | * 默认视图解析器 16 | * 17 | * @author huangyong 18 | * @since 2.3 19 | */ 20 | public class DefaultViewResolver implements ViewResolver { 21 | 22 | @Override 23 | public void resolveView(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult) { 24 | if (actionMethodResult != null) { 25 | // Action 返回值可为 View 或 Result 26 | if (actionMethodResult instanceof View) { 27 | // 若为 View,则需考虑两种视图类型(重定向 或 转发) 28 | View view = (View) actionMethodResult; 29 | if (view.isRedirect()) { 30 | // 获取路径 31 | String path = view.getPath(); 32 | // 重定向请求 33 | WebUtil.redirectRequest(path, request, response); 34 | } else { 35 | // 获取路径 36 | String path = FrameworkConstant.JSP_PATH + view.getPath(); 37 | // 初始化请求属性 38 | Map data = view.getData(); 39 | if (MapUtil.isNotEmpty(data)) { 40 | for (Map.Entry entry : data.entrySet()) { 41 | request.setAttribute(entry.getKey(), entry.getValue()); 42 | } 43 | } 44 | // 转发请求 45 | WebUtil.forwardRequest(path, request, response); 46 | } 47 | } else { 48 | // 若为 Result,则需考虑两种请求类型(文件上传 或 普通请求) 49 | Result result = (Result) actionMethodResult; 50 | if (UploadHelper.isMultipart(request)) { 51 | // 对于 multipart 类型,说明是文件上传,需要转换为 HTML 格式并写入响应中 52 | WebUtil.writeHTML(response, result); 53 | } else { 54 | // 对于其它类型,统一转换为 JSON 格式并写入响应中 55 | WebUtil.writeJSON(response, result); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/smart4j/framework/orm/DataSet.java: -------------------------------------------------------------------------------- 1 | package org.smart4j.framework.orm; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | import org.smart4j.framework.FrameworkConstant; 7 | import org.smart4j.framework.dao.DatabaseHelper; 8 | import org.smart4j.framework.dao.SqlHelper; 9 | import org.smart4j.framework.util.ArrayUtil; 10 | import org.smart4j.framework.util.MapUtil; 11 | import org.smart4j.framework.util.ObjectUtil; 12 | 13 | /** 14 | * 提供与实体相关的数据库操作 15 | * 16 | * @author huangyong 17 | * @since 1.0 18 | */ 19 | public class DataSet { 20 | 21 | /** 22 | * 查询单条数据,并转为相应类型的实体 23 | */ 24 | public static T select(Class entityClass, String condition, Object... params) { 25 | String sql = SqlHelper.generateSelectSql(entityClass, condition, ""); 26 | return DatabaseHelper.queryEntity(entityClass, sql, params); 27 | } 28 | 29 | /** 30 | * 查询多条数据,并转为相应类型的实体列表 31 | */ 32 | public static List selectList(Class entityClass) { 33 | return selectListWithConditionAndSort(entityClass, "", ""); 34 | } 35 | 36 | /** 37 | * 查询多条数据,并转为相应类型的实体列表(带有查询条件与查询参数) 38 | */ 39 | public static List selectListWithCondition(Class entityClass, String condition, Object... params) { 40 | return selectListWithConditionAndSort(entityClass, condition, "", params); 41 | } 42 | 43 | /** 44 | * 查询多条数据,并转为相应类型的实体列表(带有排序方式) 45 | */ 46 | public static List selectListWithSort(Class entityClass, String sort) { 47 | return selectListWithConditionAndSort(entityClass, "", sort); 48 | } 49 | 50 | /** 51 | * 查询多条数据,并转为相应类型的实体列表(带有查询条件、排序方式与查询参数) 52 | */ 53 | public static List selectListWithConditionAndSort(Class entityClass, String condition, String sort, Object... params) { 54 | String sql = SqlHelper.generateSelectSql(entityClass, condition, sort); 55 | return DatabaseHelper.queryEntityList(entityClass, sql, params); 56 | } 57 | 58 | /** 59 | * 查询数据条数 60 | */ 61 | public static long selectCount(Class entityClass, String condition, Object... params) { 62 | String sql = SqlHelper.generateSelectSqlForCount(entityClass, condition); 63 | return DatabaseHelper.queryCount(sql, params); 64 | } 65 | 66 | /** 67 | * 查询多条数据,并转为列表(分页方式) 68 | */ 69 | public static List selectListForPager(int pageNumber, int pageSize, Class entityClass, String condition, String sort, Object... params) { 70 | String sql = SqlHelper.generateSelectSqlForPager(pageNumber, pageSize, entityClass, condition, sort); 71 | return DatabaseHelper.queryEntityList(entityClass, sql, params); 72 | } 73 | 74 | /** 75 | * 查询多条数据,并转为映射 76 | */ 77 | public static Map selectMap(Class entityClass) { 78 | return selectMapWithPK(entityClass, FrameworkConstant.PK_NAME, "", ""); 79 | } 80 | 81 | /** 82 | * 查询多条数据,并转为映射(带有查询条件与查询参数) 83 | */ 84 | public static Map selectMapWithCondition(Class entityClass, String condition, Object... params) { 85 | return selectMapWithPK(entityClass, FrameworkConstant.PK_NAME, condition, "", params); 86 | } 87 | 88 | /** 89 | * 查询多条数据,并转为映射(带有排序方式与查询参数) 90 | * 91 | * @since 2.3.3 92 | */ 93 | public static Map selectMapWithSort(Class entityClass, String sort) { 94 | return selectMapWithPK(entityClass, FrameworkConstant.PK_NAME, "", sort); 95 | } 96 | 97 | /** 98 | * 查询多条数据,并转为映射(带有查询条件、排序方式与查询参数) 99 | */ 100 | public static Map selectMapWithConditionAndSort(Class entityClass, String condition, String sort, Object... params) { 101 | return selectMapWithPK(entityClass, FrameworkConstant.PK_NAME, condition, sort, params); 102 | } 103 | 104 | /** 105 | * 查询多条数据,并转为映射(带有主键名) 106 | */ 107 | @SuppressWarnings("unchecked") 108 | public static Map selectMapWithPK(Class entityClass, String pkName, String condition, String sort, Object... params) { 109 | Map map = new LinkedHashMap(); 110 | List list = selectListWithConditionAndSort(entityClass, condition, sort, params); 111 | for (T obj : list) { 112 | PK pk = (PK) ObjectUtil.getFieldValue(obj, pkName); 113 | map.put(pk, obj); 114 | } 115 | return map; 116 | } 117 | 118 | /** 119 | * 根据列名查询单条数据,并转为相应类型的实体 120 | */ 121 | public static T selectColumn(Class entityClass, String columnName, String condition, Object... params) { 122 | String sql = SqlHelper.generateSelectSql(entityClass, condition, ""); 123 | sql = sql.replace("*", columnName); 124 | return DatabaseHelper.queryColumn(sql, params); 125 | } 126 | 127 | /** 128 | * 根据列名查询多条数据,并转为相应类型的实体列表 129 | */ 130 | public static List selectColumnList(Class entityClass, String columnName, String condition, String sort, Object... params) { 131 | String sql = SqlHelper.generateSelectSql(entityClass, condition, sort); 132 | sql = sql.replace("*", columnName); 133 | return DatabaseHelper.queryColumnList(sql, params); 134 | } 135 | 136 | /** 137 | * 插入一条数据 138 | */ 139 | public static boolean insert(Class entityClass, Map fieldMap) { 140 | if (MapUtil.isEmpty(fieldMap)) { 141 | return true; 142 | } 143 | String sql = SqlHelper.generateInsertSql(entityClass, fieldMap.keySet()); 144 | int rows = DatabaseHelper.update(sql, fieldMap.values().toArray()); 145 | return rows > 0; 146 | } 147 | 148 | /** 149 | * 插入一个实体 150 | */ 151 | public static boolean insert(Object entity) { 152 | if (entity == null) { 153 | throw new IllegalArgumentException(); 154 | } 155 | Class entityClass = entity.getClass(); 156 | Map fieldMap = ObjectUtil.getFieldMap(entity); 157 | return insert(entityClass, fieldMap); 158 | } 159 | 160 | /** 161 | * 更新相关数据 162 | */ 163 | public static boolean update(Class entityClass, Map fieldMap, String condition, Object... params) { 164 | if (MapUtil.isEmpty(fieldMap)) { 165 | return true; 166 | } 167 | String sql = SqlHelper.generateUpdateSql(entityClass, fieldMap, condition); 168 | int rows = DatabaseHelper.update(sql, ArrayUtil.concat(fieldMap.values().toArray(), params)); 169 | return rows > 0; 170 | } 171 | 172 | /** 173 | * 更新一个实体 174 | */ 175 | public static boolean update(Object entity) { 176 | return update(entity, FrameworkConstant.PK_NAME); 177 | } 178 | 179 | /** 180 | * 更新一个实体(带有主键名) 181 | */ 182 | public static boolean update(Object entityObject, String pkName) { 183 | if (entityObject == null) { 184 | throw new IllegalArgumentException(); 185 | } 186 | Class entityClass = entityObject.getClass(); 187 | Map fieldMap = ObjectUtil.getFieldMap(entityObject); 188 | String condition = pkName + " = ?"; 189 | Object[] params = {ObjectUtil.getFieldValue(entityObject, pkName)}; 190 | return update(entityClass, fieldMap, condition, params); 191 | } 192 | 193 | /** 194 | * 删除相关数据 195 | */ 196 | public static boolean delete(Class entityClass, String condition, Object... params) { 197 | String sql = SqlHelper.generateDeleteSql(entityClass, condition); 198 | int rows = DatabaseHelper.update(sql, params); 199 | return rows > 0; 200 | } 201 | 202 | /** 203 | * 删除一个实体 204 | */ 205 | public static boolean delete(Object entityObject) { 206 | return delete(entityObject, FrameworkConstant.PK_NAME); 207 | } 208 | 209 | /** 210 | * 删除一个实体(可指定主键名) 211 | */ 212 | public static boolean delete(Object entityObject, String pkName) { 213 | if (entityObject == null) { 214 | throw new IllegalArgumentException(); 215 | } 216 | Class entityClass = entityObject.getClass(); 217 | String condition = pkName + " = ?"; 218 | Object[] params = {ObjectUtil.getFieldValue(entityObject, pkName)}; 219 | return delete(entityClass, condition, params); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /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 | import org.smart4j.framework.core.ClassHelper; 8 | import org.smart4j.framework.orm.annotation.Column; 9 | import org.smart4j.framework.orm.annotation.Entity; 10 | import org.smart4j.framework.orm.annotation.Table; 11 | import org.smart4j.framework.util.ArrayUtil; 12 | import org.smart4j.framework.util.MapUtil; 13 | import org.smart4j.framework.util.StringUtil; 14 | 15 | /** 16 | * 初始化 Entity 结构 17 | * 18 | * @author huangyong 19 | * @since 1.0 20 | */ 21 | public class EntityHelper { 22 | 23 | /** 24 | * 实体类 => 表名 25 | */ 26 | private static final Map, String> entityClassTableNameMap = new HashMap, String>(); 27 | 28 | /** 29 | * 实体类 => (字段名 => 列名) 30 | */ 31 | private static final Map, Map> entityClassFieldMapMap = new HashMap, Map>(); 32 | 33 | static { 34 | // 获取并遍历所有实体类 35 | List> entityClassList = ClassHelper.getClassListByAnnotation(Entity.class); 36 | for (Class entityClass : entityClassList) { 37 | initEntityNameMap(entityClass); 38 | initEntityFieldMapMap(entityClass); 39 | } 40 | } 41 | 42 | private static void initEntityNameMap(Class entityClass) { 43 | // 判断该实体类上是否存在 Table 注解 44 | String tableName; 45 | if (entityClass.isAnnotationPresent(Table.class)) { 46 | // 若已存在,则使用该注解中定义的表名 47 | tableName = entityClass.getAnnotation(Table.class).value(); 48 | } else { 49 | // 若不存在,则将实体类名转换为下划线风格的表名 50 | tableName = StringUtil.camelhumpToUnderline(entityClass.getSimpleName()); 51 | } 52 | entityClassTableNameMap.put(entityClass, tableName); 53 | } 54 | 55 | private static void initEntityFieldMapMap(Class entityClass) { 56 | // 获取并遍历该实体类中所有的字段(不包括父类中的方法) 57 | Field[] fields = entityClass.getDeclaredFields(); 58 | if (ArrayUtil.isNotEmpty(fields)) { 59 | // 创建一个 fieldMap(用于存放列名与字段名的映射关系) 60 | Map fieldMap = new HashMap(); 61 | for (Field field : fields) { 62 | String fieldName = field.getName(); 63 | String columnName; 64 | // 判断该字段上是否存在 Column 注解 65 | if (field.isAnnotationPresent(Column.class)) { 66 | // 若已存在,则使用该注解中定义的列名 67 | columnName = field.getAnnotation(Column.class).value(); 68 | } else { 69 | // 若不存在,则将字段名转换为下划线风格的列名 70 | columnName = StringUtil.camelhumpToUnderline(fieldName); 71 | } 72 | fieldMap.put(fieldName, columnName); 73 | } 74 | entityClassFieldMapMap.put(entityClass, fieldMap); 75 | } 76 | } 77 | 78 | public static String getTableName(Class entityClass) { 79 | return entityClassTableNameMap.get(entityClass); 80 | } 81 | 82 | public static Map getFieldMap(Class entityClass) { 83 | return entityClassFieldMapMap.get(entityClass); 84 | } 85 | 86 | public static Map getColumnMap(Class entityClass) { 87 | return MapUtil.invert(getFieldMap(entityClass)); 88 | } 89 | 90 | public static String getColumnName(Class entityClass, String fieldName) { 91 | String columnName = getFieldMap(entityClass).get(fieldName); 92 | return StringUtil.isNotEmpty(columnName) ? columnName : fieldName; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /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 | } 20 | -------------------------------------------------------------------------------- /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 | } 18 | -------------------------------------------------------------------------------- /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 | } 20 | -------------------------------------------------------------------------------- /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 | } 21 | -------------------------------------------------------------------------------- /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 pluginList = new ArrayList(); 22 | 23 | /** 24 | * 获取 ClassScanner 25 | */ 26 | private static final ClassScanner classScanner = InstanceFactory.getClassScanner(); 27 | 28 | static { 29 | try { 30 | // 获取并遍历所有的插件类(实现了 Plugin 接口的类) 31 | List> 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 getPluginList() { 49 | return pluginList; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /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> getTargetClassList(); 15 | } 16 | -------------------------------------------------------------------------------- /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 | *
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 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/smart4j/framework/test/OrderedRunner.java: -------------------------------------------------------------------------------- 1 | package org.smart4j.framework.test; 2 | 3 | import java.util.Collections; 4 | import java.util.Comparator; 5 | import java.util.List; 6 | import org.junit.runners.BlockJUnit4ClassRunner; 7 | import org.junit.runners.model.FrameworkMethod; 8 | import org.junit.runners.model.InitializationError; 9 | import org.smart4j.framework.HelperLoader; 10 | import org.smart4j.framework.test.annotation.TestOrder; 11 | 12 | /** 13 | * 使测试用例可按顺序执行 14 | * 15 | * @author huangyong 16 | * @since 1.0 17 | */ 18 | public class OrderedRunner extends BlockJUnit4ClassRunner { 19 | 20 | /** 21 | * 定义一个静态变量,确保 computeTestMethods() 中的排序逻辑只运行一次(JUnit 会调用两次) 22 | */ 23 | private static List testMethodList; 24 | 25 | public OrderedRunner(Class cls) throws InitializationError { 26 | // 调用父类构造器 27 | super(cls); 28 | // 初始化 Helper 类 29 | HelperLoader.init(); 30 | } 31 | 32 | @Override 33 | protected List computeTestMethods() { 34 | if (testMethodList == null) { 35 | // 获取带有 Test 注解的方法 36 | testMethodList = super.computeTestMethods(); 37 | // 获取测试方法上的 Order 注解,并对所有的测试方法重新排序 38 | Collections.sort(testMethodList, new Comparator() { 39 | @Override 40 | public int compare(FrameworkMethod m1, FrameworkMethod m2) { 41 | TestOrder o1 = m1.getAnnotation(TestOrder.class); 42 | TestOrder o2 = m2.getAnnotation(TestOrder.class); 43 | if (o1 == null || o2 == null) { 44 | return 0; 45 | } 46 | return o1.value() - o2.value(); 47 | } 48 | }); 49 | } 50 | return testMethodList; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/smart4j/framework/test/annotation/TestOrder.java: -------------------------------------------------------------------------------- 1 | package org.smart4j.framework.test.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 TestOrder { 17 | 18 | int value(); 19 | } 20 | -------------------------------------------------------------------------------- /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 flagContainer = new ThreadLocal() { 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 | } 67 | -------------------------------------------------------------------------------- /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 | } 18 | -------------------------------------------------------------------------------- /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 | } 18 | -------------------------------------------------------------------------------- /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 boolean contains(T[] array, T obj) { 38 | return ArrayUtils.contains(array, obj); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /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 | } 198 | -------------------------------------------------------------------------------- /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 | } 85 | -------------------------------------------------------------------------------- /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 | } 108 | -------------------------------------------------------------------------------- /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 | } 28 | -------------------------------------------------------------------------------- /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 | } 104 | -------------------------------------------------------------------------------- /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 | } 179 | -------------------------------------------------------------------------------- /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 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 fromJSON(String json, Class 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 | } 47 | -------------------------------------------------------------------------------- /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 Map invert(Map source) { 33 | Map target = null; 34 | if (isNotEmpty(source)) { 35 | target = new LinkedHashMap(source.size()); 36 | for (Map.Entry entry : source.entrySet()) { 37 | target.put(entry.getValue(), entry.getKey()); 38 | } 39 | } 40 | return target; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /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 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 getFieldMap(Object obj) { 89 | return getFieldMap(obj, true); 90 | } 91 | 92 | /** 93 | * 获取对象的字段映射(字段名 => 字段值) 94 | */ 95 | public static Map getFieldMap(Object obj, boolean isStaticIgnored) { 96 | Map fieldMap = new LinkedHashMap(); 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 | } 109 | -------------------------------------------------------------------------------- /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 loadPropsToMap(String propsPath) { 60 | Map map = new HashMap(); 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 getMap(Properties props, String prefix) { 132 | Map kvMap = new LinkedHashMap(); 133 | Set 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 | } 145 | -------------------------------------------------------------------------------- /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 | logger.error("释放资源出错!", e); 40 | } 41 | } 42 | } 43 | 44 | /** 45 | * 从输入流中获取字符串 46 | */ 47 | public static String getString(InputStream is) { 48 | StringBuilder sb = new StringBuilder(); 49 | try { 50 | BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 51 | String line; 52 | while ((line = reader.readLine()) != null) { 53 | sb.append(line); 54 | } 55 | } catch (Exception e) { 56 | logger.error("Stream 转 String 出错!", e); 57 | throw new RuntimeException(e); 58 | } 59 | return sb.toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /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 | } 164 | -------------------------------------------------------------------------------- /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 | import javax.imageio.ImageIO; 18 | import javax.servlet.ServletOutputStream; 19 | import javax.servlet.http.Cookie; 20 | import javax.servlet.http.HttpServletRequest; 21 | import javax.servlet.http.HttpServletResponse; 22 | import org.apache.commons.io.FilenameUtils; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import org.smart4j.framework.FrameworkConstant; 26 | 27 | /** 28 | * Web 操作工具类 29 | * 30 | * @author huangyong 31 | * @since 1.0 32 | */ 33 | public class WebUtil { 34 | 35 | private static final Logger logger = LoggerFactory.getLogger(WebUtil.class); 36 | 37 | /** 38 | * 将数据以 JSON 格式写入响应中 39 | */ 40 | public static void writeJSON(HttpServletResponse response, Object data) { 41 | try { 42 | // 设置响应头 43 | response.setContentType("application/json"); // 指定内容类型为 JSON 格式 44 | response.setCharacterEncoding(FrameworkConstant.UTF_8); // 防止中文乱码 45 | // 向响应中写入数据 46 | PrintWriter writer = response.getWriter(); 47 | writer.write(JsonUtil.toJSON(data)); // 转为 JSON 字符串 48 | writer.flush(); 49 | writer.close(); 50 | } catch (Exception e) { 51 | logger.error("在响应中写数据出错!", e); 52 | throw new RuntimeException(e); 53 | } 54 | } 55 | 56 | /** 57 | * 将数据以 HTML 格式写入响应中(在 JS 中获取的是 JSON 字符串,而不是 JSON 对象) 58 | */ 59 | public static void writeHTML(HttpServletResponse response, Object data) { 60 | try { 61 | // 设置响应头 62 | response.setContentType("text/html"); // 指定内容类型为 HTML 格式 63 | response.setCharacterEncoding(FrameworkConstant.UTF_8); // 防止中文乱码 64 | // 向响应中写入数据 65 | PrintWriter writer = response.getWriter(); 66 | writer.write(JsonUtil.toJSON(data)); // 转为 JSON 字符串 67 | writer.flush(); 68 | writer.close(); 69 | } catch (Exception e) { 70 | logger.error("在响应中写数据出错!", e); 71 | throw new RuntimeException(e); 72 | } 73 | } 74 | 75 | /** 76 | * 从请求中获取所有参数(当参数名重复时,用后者覆盖前者) 77 | */ 78 | public static Map getRequestParamMap(HttpServletRequest request) { 79 | Map paramMap = new LinkedHashMap(); 80 | try { 81 | String method = request.getMethod(); 82 | if (method.equalsIgnoreCase("put") || method.equalsIgnoreCase("delete")) { 83 | String queryString = CodecUtil.decodeURL(StreamUtil.getString(request.getInputStream())); 84 | if (StringUtil.isNotEmpty(queryString)) { 85 | String[] qsArray = StringUtil.splitString(queryString, "&"); 86 | if (ArrayUtil.isNotEmpty(qsArray)) { 87 | for (String qs : qsArray) { 88 | String[] array = StringUtil.splitString(qs, "="); 89 | if (ArrayUtil.isNotEmpty(array) && array.length == 2) { 90 | String paramName = array[0]; 91 | String paramValue = array[1]; 92 | if (checkParamName(paramName)) { 93 | if (paramMap.containsKey(paramName)) { 94 | paramValue = paramMap.get(paramName) + StringUtil.SEPARATOR + paramValue; 95 | } 96 | paramMap.put(paramName, paramValue); 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } else { 103 | Enumeration paramNames = request.getParameterNames(); 104 | while (paramNames.hasMoreElements()) { 105 | String paramName = paramNames.nextElement(); 106 | if (checkParamName(paramName)) { 107 | String[] paramValues = request.getParameterValues(paramName); 108 | if (ArrayUtil.isNotEmpty(paramValues)) { 109 | if (paramValues.length == 1) { 110 | paramMap.put(paramName, paramValues[0]); 111 | } else { 112 | StringBuilder paramValue = new StringBuilder(""); 113 | for (int i = 0; i < paramValues.length; i++) { 114 | paramValue.append(paramValues[i]); 115 | if (i != paramValues.length - 1) { 116 | paramValue.append(StringUtil.SEPARATOR); 117 | } 118 | } 119 | paramMap.put(paramName, paramValue.toString()); 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } catch (Exception e) { 126 | logger.error("获取请求参数出错!", e); 127 | throw new RuntimeException(e); 128 | } 129 | return paramMap; 130 | } 131 | 132 | private static boolean checkParamName(String paramName) { 133 | return !paramName.equals("_"); // 忽略 jQuery 缓存参数 134 | } 135 | 136 | /** 137 | * 转发请求 138 | */ 139 | public static void forwardRequest(String path, HttpServletRequest request, HttpServletResponse response) { 140 | try { 141 | request.getRequestDispatcher(path).forward(request, response); 142 | } catch (Exception e) { 143 | logger.error("转发请求出错!", e); 144 | throw new RuntimeException(e); 145 | } 146 | } 147 | 148 | /** 149 | * 重定向请求 150 | */ 151 | public static void redirectRequest(String path, HttpServletRequest request, HttpServletResponse response) { 152 | try { 153 | response.sendRedirect(request.getContextPath() + path); 154 | } catch (Exception e) { 155 | logger.error("重定向请求出错!", e); 156 | throw new RuntimeException(e); 157 | } 158 | } 159 | 160 | /** 161 | * 发送错误代码 162 | */ 163 | public static void sendError(int code, String message, HttpServletResponse response) { 164 | try { 165 | response.sendError(code, message); 166 | } catch (Exception e) { 167 | logger.error("发送错误代码出错!", e); 168 | throw new RuntimeException(e); 169 | } 170 | } 171 | 172 | /** 173 | * 判断是否为 AJAX 请求 174 | */ 175 | public static boolean isAJAX(HttpServletRequest request) { 176 | return request.getHeader("X-Requested-With") != null; 177 | } 178 | 179 | /** 180 | * 获取请求路径 181 | */ 182 | public static String getRequestPath(HttpServletRequest request) { 183 | String servletPath = request.getServletPath(); 184 | String pathInfo = StringUtil.defaultIfEmpty(request.getPathInfo(), ""); 185 | return servletPath + pathInfo; 186 | } 187 | 188 | /** 189 | * 从 Cookie 中获取数据 190 | */ 191 | public static String getCookie(HttpServletRequest request, String name) { 192 | String value = ""; 193 | try { 194 | Cookie[] cookieArray = request.getCookies(); 195 | if (cookieArray != null) { 196 | for (Cookie cookie : cookieArray) { 197 | if (StringUtil.isNotEmpty(name) && name.equals(cookie.getName())) { 198 | value = CodecUtil.decodeURL(cookie.getValue()); 199 | break; 200 | } 201 | } 202 | } 203 | } catch (Exception e) { 204 | logger.error("获取 Cookie 出错!", e); 205 | throw new RuntimeException(e); 206 | } 207 | return value; 208 | } 209 | 210 | /** 211 | * 下载文件 212 | */ 213 | public static void downloadFile(HttpServletResponse response, String filePath) { 214 | try { 215 | String originalFileName = FilenameUtils.getName(filePath); 216 | String downloadedFileName = new String(originalFileName.getBytes("GBK"), "ISO8859_1"); // 防止中文乱码 217 | 218 | response.setContentType("application/octet-stream"); 219 | response.addHeader("Content-Disposition", "attachment;filename=\"" + downloadedFileName + "\""); 220 | 221 | InputStream inputStream = new BufferedInputStream(new FileInputStream(filePath)); 222 | OutputStream outputStream = new BufferedOutputStream(response.getOutputStream()); 223 | StreamUtil.copyStream(inputStream, outputStream); 224 | } catch (Exception e) { 225 | logger.error("下载文件出错!", e); 226 | throw new RuntimeException(e); 227 | } 228 | } 229 | 230 | /** 231 | * 设置 Redirect URL 到 Session 中 232 | */ 233 | public static void setRedirectUrl(HttpServletRequest request, String sessionKey) { 234 | if (!isAJAX(request)) { 235 | String requestPath = getRequestPath(request); 236 | request.getSession().setAttribute(sessionKey, requestPath); 237 | } 238 | } 239 | 240 | /** 241 | * 创建验证码 242 | */ 243 | public static String createCaptcha(HttpServletResponse response) { 244 | StringBuilder captcha = new StringBuilder(); 245 | try { 246 | // 参数初始化 247 | int width = 60; // 验证码图片的宽度 248 | int height = 25; // 验证码图片的高度 249 | int codeCount = 4; // 验证码字符个数 250 | int codeX = width / (codeCount + 1); // 字符横向间距 251 | int codeY = height - 4; // 字符纵向间距 252 | int fontHeight = height - 2; // 字体高度 253 | int randomSeed = 10; // 随机数种子 254 | char[] codeSequence = { // 验证码中可出现的字符 255 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 256 | }; 257 | // 创建图像 258 | BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 259 | Graphics2D g = bi.createGraphics(); 260 | // 将图像填充为白色 261 | g.setColor(Color.WHITE); 262 | g.fillRect(0, 0, width, height); 263 | // 设置字体 264 | g.setFont(new Font("Courier New", Font.BOLD, fontHeight)); 265 | // 绘制边框 266 | g.setColor(Color.BLACK); 267 | g.drawRect(0, 0, width - 1, height - 1); 268 | // 产生随机干扰线(160条) 269 | g.setColor(Color.WHITE); 270 | // 创建随机数生成器 271 | Random random = new Random(); 272 | for (int i = 0; i < 160; i++) { 273 | int x = random.nextInt(width); 274 | int y = random.nextInt(height); 275 | int xl = random.nextInt(12); 276 | int yl = random.nextInt(12); 277 | g.drawLine(x, y, x + xl, y + yl); 278 | } 279 | // 生成随机验证码 280 | int red, green, blue; 281 | for (int i = 0; i < codeCount; i++) { 282 | // 获取随机验证码 283 | String validateCode = String.valueOf(codeSequence[random.nextInt(randomSeed)]); 284 | // 随机构造颜色值 285 | red = random.nextInt(255); 286 | green = random.nextInt(255); 287 | blue = random.nextInt(255); 288 | // 将带有颜色的验证码绘制到图像中 289 | g.setColor(new Color(red, green, blue)); 290 | g.drawString(validateCode, (i + 1) * codeX - 6, codeY); 291 | // 将产生的随机数拼接起来 292 | captcha.append(validateCode); 293 | } 294 | // 禁止图像缓存 295 | response.setHeader("Cache-Control", "no-store"); 296 | response.setHeader("Pragma", "no-cache"); 297 | response.setDateHeader("Expires", 0); 298 | // 设置响应类型为 JPEG 图片 299 | response.setContentType("image/jpeg"); 300 | // 将缓冲图像写到 Servlet 输出流中 301 | ServletOutputStream sos = response.getOutputStream(); 302 | ImageIO.write(bi, "jpeg", sos); 303 | sos.close(); 304 | } catch (Exception e) { 305 | logger.error("创建验证码出错!", e); 306 | throw new RuntimeException(e); 307 | } 308 | return captcha.toString(); 309 | } 310 | 311 | /** 312 | * 是否为 IE 浏览器 313 | */ 314 | public boolean isIE(HttpServletRequest request) { 315 | String agent = request.getHeader("User-Agent"); 316 | return agent != null && agent.contains("MSIE"); 317 | } 318 | } 319 | --------------------------------------------------------------------------------