diff --git a/.dockerignore b/.dockerignore index 82dfbbdd0ec58c6ec781ede55f59fa6ea1d692e4..986d4b56114d28effcd81fc34bae734162692f76 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,3 @@ -* -!starter/target/starter-3.0 +* +!starter/target/starter-3.0 !docker \ No newline at end of file diff --git a/.gitignore b/.gitignore index edeb15a2bca44834c34fd2bc64da23947ae46d07..333643aae3fc5a5b21cd11f4f224cdb753cb09ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,28 @@ -**/target/ -*/jpress-addon-club/ -*/jpress-addon-articlemeta/ -*/jpress-addon-wechatlogin/ -*/jpress-addon-wtask/ -*/jpress-addon-dcode/ -*/jpress-addon-smartprogram/ -*/jpress-addon-keygen/ -*/jpress-addon-newprod/ -starter-dev/ -starter-ent/ -.idea -*.iml -.project -.settings -starter/**/jboot.properties -install.lock -*.jar -*.log -.logs -logs -*.iws -*.classpath -.DS_Store -*.patch -~$* -*/*.jar -docker_volumes/ +**/target/ +*/jpress-addon-club/ +*/jpress-addon-articlemeta/ +*/jpress-addon-wechatlogin/ +*/jpress-addon-wtask/ +*/jpress-addon-dcode/ +*/jpress-addon-smartprogram/ +*/jpress-addon-keygen/ +*/jpress-addon-newprod/ +starter-dev/ +starter-ent/ +.idea +*.iml +.project +.settings +starter/**/jboot.properties +install.lock +*.jar +*.log +.logs +logs +*.iws +*.classpath +.DS_Store +*.patch +~$* +*/*.jar +docker_volumes/ diff --git a/Dockerfile b/Dockerfile index fe56f405a8f3643da9ca9c12c5e86358fa1a5a90..351f0f845dfd06265097d9ab8a4a106ead69bcbf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,18 @@ -FROM fuhai/jpress-base:v1.4 -LABEL maintainer="Michael Yang" - -WORKDIR /opt/jpress - -COPY ./starter/target/starter-3.0/ /opt/jpress/ -COPY ./docker/files/jpress.sh /opt/jpress/jpress.sh -COPY ./docker/files/jboot.properties /opt/jpress/config/jboot.properties - - -RUN chmod +x /opt/jpress/jpress.sh && \ - rm -rf /opt/jpress/jpress.bat && \ - rm -rf /opt/jpress/config/undertow.txt && \ - rm -rf /opt/jpress/config/install.lock - -EXPOSE 8080 - +FROM fuhai/jpress-base:v1.4 +LABEL maintainer="Michael Yang" + +WORKDIR /opt/jpress + +COPY ./starter/target/starter-3.0/ /opt/jpress/ +COPY ./docker/files/jpress.sh /opt/jpress/jpress.sh +COPY ./docker/files/jboot.properties /opt/jpress/config/jboot.properties + + +RUN chmod +x /opt/jpress/jpress.sh && \ + rm -rf /opt/jpress/jpress.bat && \ + rm -rf /opt/jpress/config/undertow.txt && \ + rm -rf /opt/jpress/config/install.lock + +EXPOSE 8080 + CMD ["/opt/jpress/jpress.sh", "start"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index e8a5509b20d974587560e4afd212f6b20cf30c7d..3e0caaf5cf0d3e1abe71298e66d8d4a8771ee4cd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,165 +1,165 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md index 0c7468997996b48cacfa43007c1158df0e41838d..02ffe438bd1d34bc94ccc30f479e40b235b13c01 100644 --- a/README.md +++ b/README.md @@ -1,209 +1,209 @@ -![](./doc/images/screenshot.png) - - -

JPress

- -

-一个使用 Java 开发的类似 WordPress 的产品,并在此基础上增加了电商的功能。 -

- - -

-release -release -commit -issues -license -

- -## 功能 - -#### 内容相关 -- 文章管理 -- 文章分类 -- 文章标签 -- 文章搜索(支持 sql like、Lucene、es、OpenSearch) -- 用户投稿 -- 页面管理 -- 评论管理 -- 附件管理 - - -#### 电商相关 -- 产品管理 -- 产品分类 -- 产品标签 -- 产品搜索(支持 sql like、Lucene、es、OpenSearch) -- 产品分销 -- 会员管理 -- 订单管理 -- 分销管理 -- 提现管理 -- 优惠券管理 -- 支付配置 -- 物流配置 - - -#### 用户相关 -- 用户管理 -- 会员管理 -- 权限管理 -- 订单管理 -- 用户标签 -- 短信群发 -- 邮件群发 - - -#### 系统相关 -- 模板管理 -- 插件管理 -- 微信管理 -- 系统管理 - - -## 特点 - -#### 模板 - -- 模板在线安装、卸载 -- 模板在线启用、切换 -- 在线编辑及实时生效 -- 完善的模板开发文档 -- 极致的模板开发体验 - - -#### 插件 - -- 插件在线安装、卸载 -- 插件在线启用、停止 -- 插件在线更新 -- 支持在插件里添加新的 Controller -- 支持在插件里添加新的 Handler -- 支持在插件里添加新的 Interceptor -- 支持在插件里添加新的 Html、Css 和 Js -- 支持在插件里创建新的数据库表以及对应的 Model -- 支持在插件里链接不同的数据库 -- 支持通过插件动态扩展后台菜单和用户中心菜单 -- 插件扩展的菜单支持用户权限设置的管理 -- 插件被停止:该插件的所有Controller、Handler、Intercepter 自动被移除 -- 插件被卸载:该插件的所有资源全部被删除 - - -#### 用户 - -- 独立登录、注册入口 -- 手机短信、邮箱激活功能 -- 用户中心(投稿、文章管理、评论管理、个人资料管理等) -- 第三方登录:微信、QQ、钉钉、oschina、GitHub等 -- 微信浏览时,通过微信授权自动获取用户信息 - - -#### 角色和权限 - -- 角色管理 -- 全自动、免维护的权限字典(自动发现后台路由、插件安装卸载自动分配对应) -- 角色和权限的分配 -- 用户多角色功能 -- 超级管理员 - - -#### 微信 - -- 微信公众号对接 -- 微信公众号关键字自动回复 -- 微信公众号菜单设置 -- 微信公众号运营插件 -- 通过运用插件灵活扩展各种微信营销功能 -- 微信小程序对接、和配置 - - -#### SEO - -- 每篇文章和页面独立的SEO设置 -- Baidu API 的实时推送 -- Baidu 和 Google 的自动 Ping 提交 -- Sitemap 自动生成、后台支持自定义的开启和关闭 -- robots.txt 爬虫蜘蛛的支持 -- 整站伪静态支持,支持自定义开后缀 - - -#### 其他 - -- WordPress、Hexo、Jekyll、微信公众号等文章一键导入 -- 编写文章随意切换 CKEditor 和 Markdown 编辑 -- 最大化、沉侵式的文章编写体验 -- Docker 一键部署 -- 阿里云、腾讯云 CDN 在线配置 -- 阿里云、腾讯云短信验证(用户注册手机验证) -- 附件自动可配置自动同步阿里云 OSS -- 完善的API接口配置管理 -- ... (更多等你发现) - - -## 交流 - -- 官网:[http://www.jpress.io](http://www.jpress.io) -- 论坛社区:[点击这里](http://www.jpress.io/club) -- 插件列表:[点击这里](http://www.jpress.io/article/category/plugin) -- 模板列表:[点击这里](http://www.jpress.io/article/category/template) -- QQ群:591396171 ,288397536 - - -## 帮助文档 - -- [了解JPress](http://www.jpress.io) -- [快速开始](http://www.jpress.io/article/34) -- [安装](http://www.jpress.io/article/34) -- [升级](./doc/upgrade.md) -- [使用](./doc/manual.md) -- [模板开发](http://www.jpress.io/article/39) -- [二次开发](http://www.jpress.io/article/68) -- [插件开发](http://www.jpress.io/article/54) -- [微信运营插件开发](http://www.jpress.io/article/65) -- [微信小程序开发](http://www.jpress.io/article/67) -- [视频教程](http://www.jpress.io/article/category/course) -- [常见问题](./doc/faq.md) -- [JPress-VIP 会员](./doc/vip.md) - -## 运行JPress - - -**在 Docker 上运行** - -``` -curl -O https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml && docker-compose up -d -``` - -**在 Linux 上一键安装** - -``` -wget https://gitee.com/fuhai/jpress/raw/master/install.sh && bash install.sh -``` - -> 视频教程链接: https://pan.baidu.com/s/1ciA2DglE-JV-YiU3ojtmew 提取码: 37g5 - - -**通过 Eclipse 或者 Idea 等开发工具运行** - -- 1、在电脑安装好 Java、Maven 等开发环境 -- 2、将源码下载、并导入 eclipse 或者 idea -- 3、在项目的**根目录**,执行 `mvn clean install` 命令进行编译 -- 4、在开发工具,右键运行 `starter/src/main/java/io.jpress.Starter` 下的 `main()` 方法 -- 5、通过浏览器访问 `http://127.0.0.1:8080`,进行自动安装 - - -> 可能遇到的问题: -> -> 1、执行 `mvn clean` 后,再次运行 JPress,JPress 会重新走安装流程。 -> -> 解决方案: jpress 在安装过程中,会在 `starter/target/classes` 目录下生成的 `jboot.properties` 和 `install.lock` 文件,我们需要把这两个文件复制到 `starter/src/main/resource` 目录下。 因为,jpress 是否安装决定在这两个文件,当我们执行 `mvn clean` 命令时,maven 会清除 target 下的所有文件,从而使 JPress 会再次走安装流程。 - - - - -## 微信交流群 - -![](./doc/images/jpress-wechat-group.png) - - - +![](./doc/images/screenshot.png) + + +

JPress

+ +

+一个使用 Java 开发的类似 WordPress 的产品,并在此基础上增加了电商的功能。 +

+ + +

+release +release +commit +issues +license +

+ +## 功能 + +#### 内容相关 +- 文章管理 +- 文章分类 +- 文章标签 +- 文章搜索(支持 sql like、Lucene、es、OpenSearch) +- 用户投稿 +- 页面管理 +- 评论管理 +- 附件管理 + + +#### 电商相关 +- 产品管理 +- 产品分类 +- 产品标签 +- 产品搜索(支持 sql like、Lucene、es、OpenSearch) +- 产品分销 +- 会员管理 +- 订单管理 +- 分销管理 +- 提现管理 +- 优惠券管理 +- 支付配置 +- 物流配置 + + +#### 用户相关 +- 用户管理 +- 会员管理 +- 权限管理 +- 订单管理 +- 用户标签 +- 短信群发 +- 邮件群发 + + +#### 系统相关 +- 模板管理 +- 插件管理 +- 微信管理 +- 系统管理 + + +## 特点 + +#### 模板 + +- 模板在线安装、卸载 +- 模板在线启用、切换 +- 在线编辑及实时生效 +- 完善的模板开发文档 +- 极致的模板开发体验 + + +#### 插件 + +- 插件在线安装、卸载 +- 插件在线启用、停止 +- 插件在线更新 +- 支持在插件里添加新的 Controller +- 支持在插件里添加新的 Handler +- 支持在插件里添加新的 Interceptor +- 支持在插件里添加新的 Html、Css 和 Js +- 支持在插件里创建新的数据库表以及对应的 Model +- 支持在插件里链接不同的数据库 +- 支持通过插件动态扩展后台菜单和用户中心菜单 +- 插件扩展的菜单支持用户权限设置的管理 +- 插件被停止:该插件的所有Controller、Handler、Intercepter 自动被移除 +- 插件被卸载:该插件的所有资源全部被删除 + + +#### 用户 + +- 独立登录、注册入口 +- 手机短信、邮箱激活功能 +- 用户中心(投稿、文章管理、评论管理、个人资料管理等) +- 第三方登录:微信、QQ、钉钉、oschina、GitHub等 +- 微信浏览时,通过微信授权自动获取用户信息 + + +#### 角色和权限 + +- 角色管理 +- 全自动、免维护的权限字典(自动发现后台路由、插件安装卸载自动分配对应) +- 角色和权限的分配 +- 用户多角色功能 +- 超级管理员 + + +#### 微信 + +- 微信公众号对接 +- 微信公众号关键字自动回复 +- 微信公众号菜单设置 +- 微信公众号运营插件 +- 通过运用插件灵活扩展各种微信营销功能 +- 微信小程序对接、和配置 + + +#### SEO + +- 每篇文章和页面独立的SEO设置 +- Baidu API 的实时推送 +- Baidu 和 Google 的自动 Ping 提交 +- Sitemap 自动生成、后台支持自定义的开启和关闭 +- robots.txt 爬虫蜘蛛的支持 +- 整站伪静态支持,支持自定义开后缀 + + +#### 其他 + +- WordPress、Hexo、Jekyll、微信公众号等文章一键导入 +- 编写文章随意切换 CKEditor 和 Markdown 编辑 +- 最大化、沉侵式的文章编写体验 +- Docker 一键部署 +- 阿里云、腾讯云 CDN 在线配置 +- 阿里云、腾讯云短信验证(用户注册手机验证) +- 附件自动可配置自动同步阿里云 OSS +- 完善的API接口配置管理 +- ... (更多等你发现) + + +## 交流 + +- 官网:[http://www.jpress.io](http://www.jpress.io) +- 论坛社区:[点击这里](http://www.jpress.io/club) +- 插件列表:[点击这里](http://www.jpress.io/article/category/plugin) +- 模板列表:[点击这里](http://www.jpress.io/article/category/template) +- QQ群:591396171 ,288397536 + + +## 帮助文档 + +- [了解JPress](http://www.jpress.io) +- [快速开始](http://www.jpress.io/article/34) +- [安装](http://www.jpress.io/article/34) +- [升级](./doc/upgrade.md) +- [使用](./doc/manual.md) +- [模板开发](http://www.jpress.io/article/39) +- [二次开发](http://www.jpress.io/article/68) +- [插件开发](http://www.jpress.io/article/54) +- [微信运营插件开发](http://www.jpress.io/article/65) +- [微信小程序开发](http://www.jpress.io/article/67) +- [视频教程](http://www.jpress.io/article/category/course) +- [常见问题](./doc/faq.md) +- [JPress-VIP 会员](./doc/vip.md) + +## 运行JPress + + +**在 Docker 上运行** + +``` +curl -O https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml && docker-compose up -d +``` + +**在 Linux 上一键安装** + +``` +wget https://gitee.com/fuhai/jpress/raw/master/install.sh && bash install.sh +``` + +> 视频教程链接: https://pan.baidu.com/s/1ciA2DglE-JV-YiU3ojtmew 提取码: 37g5 + + +**通过 Eclipse 或者 Idea 等开发工具运行** + +- 1、在电脑安装好 Java、Maven 等开发环境 +- 2、将源码下载、并导入 eclipse 或者 idea +- 3、在项目的**根目录**,执行 `mvn clean install` 命令进行编译 +- 4、在开发工具,右键运行 `starter/src/main/java/io.jpress.Starter` 下的 `main()` 方法 +- 5、通过浏览器访问 `http://127.0.0.1:8080`,进行自动安装 + + +> 可能遇到的问题: +> +> 1、执行 `mvn clean` 后,再次运行 JPress,JPress 会重新走安装流程。 +> +> 解决方案: jpress 在安装过程中,会在 `starter/target/classes` 目录下生成的 `jboot.properties` 和 `install.lock` 文件,我们需要把这两个文件复制到 `starter/src/main/resource` 目录下。 因为,jpress 是否安装决定在这两个文件,当我们执行 `mvn clean` 命令时,maven 会清除 target 下的所有文件,从而使 JPress 会再次走安装流程。 + + + + +## 微信交流群 + +![](./doc/images/jpress-wechat-group.png) + + + diff --git a/changes.txt b/changes.txt index 1aadd754df9942fa84285d3eed3d1f8627aa9b7e..4667dee3553e48495e00d8e47224fb19fd9232b1 100644 --- a/changes.txt +++ b/changes.txt @@ -1,356 +1,356 @@ -jpress v3.2.3: -新增:新增用户绑定账号后,取消绑定的功能 -新增:尝试性支持 jdk11 ~ jdk14 -修复:快递100查询时因签名未转大写,造成签名错误而无法正常显示快递信息问题。感谢 @lixuanqun -修复:下载的附件目录不规范的问题,感谢 @Retire -优化:优化 OauthConnector,支持可以自由配置回调域名 -优化:优化 违法关键字 词库 - - - -jpress v3.2.2: -优化:JPress 的安装和升级流程 -优化:重构第三方登录的授权流程 -优化:优化产品的相关指令和注释 -修复:使用 QQ 第三方登录的时候无法正常登录的问题 -修复:正确设置微信小程序、第三方登录等的首次用户状态 -修复:当产品详情页引用 product.js 但是未启用 Swiper 的时候出错的问题 -修复:checkout 页面无法正确删除产品的问题 -修复:JPress 低版本升级到最新版本是,倘若最后一步不填写管理员账号密码会出错的问题 - - - -jpress v3.2.1: -新增:模板预览功能,前端可以通过 url 访问指定已经安装的模板 -优化:升级 ckeditor 到最新版本,以支持 word 的复制粘贴功能 -优化:通过 QQ 进行第三方登录时,发生错误提示不明显的问题 -修复:分销用户无法正确获取分销金额的问题 -修复:ArticleService.findListByCategoryId() 的 count 参数不起作用的问题 -修复:通过 paypal 进行支付发生错误的问题 -修复:加购物车返回的 Json 内容不正确的问题,感谢 @一座城你说你不懂 -修复:通过 Github 第三方登录无法获取正确的用户数据的问题 - - - -jpress v3.2.0: -新增:添加一个全新的插件:留言插件,方便网站使用其增强 "留言" 功能,同时方便新手作为一个参考去开发自己的插件,感谢作者 @安杰 -新增:可以通过 URL 直接访问模板页面的功能,假设存在模板 abc.html,增可以直接通过 http://domain/abc 去访问。 -新增:默认模板 calmlog 新增文章搜索功能 -新增:产品详情页新增 URL 分享按钮,当产品启用分销时,分销的 URL 可以获得相应的佣金。 -优化:重构 TemplateManager,使其代码更加简洁 -优化:优化 #CategoriesDirective 指令,防止在产品页面使用时出现类型转换错误的问题 -优化:对 BaseProductInfoQuerier 进行重构,方便在开发插件的时候可以获取更多的信息 -优化:删除 ArticleServiceProvider 中多余的不必要的注解 -优化:对 AddonControllerManager 进行优化,插件的 Controller 的 viewPath 不用必须为 "/" 的问题 -优化:对 微信支付的后台配置添加相应的文字说明,方便使用者更加清晰的去使用 -优化:对 订单和支付等内容进行 "固化",不允许自己去支付别人的订单。 -修复:当产品启用 Lucene 搜索引擎后,无法搜索其内容的问题 -修复:当产品更新的时候,缓存无法及时清空的问题 -修复:当产品和文章同时开启 ElasticSearch 搜索引擎的时候,会出现索引覆盖的问题 -修复:对用户进行删除的时候,没有删除用户的 OpenId,导致该用户每次访问都会创建新的用户的问题 -文档:添加 JPress 升级的相关文档 - - - -jpress v3.1.1: -新增:订单超时的时间设置功能,超时订单自动被关闭 -新增:新增产品分类的标签 #productCategoryList,用于读取产品分类内容 -优化:优化订单列表的文字样式以及发货按钮的显示逻辑 -优化:移除 AdminOrderDetailPgeRender 和 UCenterOrderDetailPageRender 的配置支持 -优化:优化 install.sh ,在某些时候无法正常安装的问题 -优化:优化 docker-compose.yml ,升级 mysql image 到 5.7 -优化:用户推出方法 doLogout() 修改为 logout() -优化:优化插件模块,在某些极端情况下出现无法删除插件内容的问题 -优化:升级jboot、fastjson、jcseg等相关依赖到最新版本 -修复:购买产品时,默认地址不正确的问题 -修复:对未支付订单重新支付时,无法选择新地址的问题 -修复:修复代码生成器生成的代码内容编辑的 URL 路径错误的问题,感谢 @安杰 -修复:代码生成器生成的代码中,进行批量删除时出现404的问题,感谢 @安杰 - - - -jpress v3.1.0: -新增:新增 GlobalInterceptor 注解,插件拦截器必须通过此声明才能设置为全局拦截器 -新增:AddonUtil 新增 addSharedFunction() 和 removeSharedFunction() 方法,用于对插件共享模板的新增和移除 -新增:AddonUtil 新增 getViewPath() 方法,用于获取插件的文件路径 -新增:用户注册新增 "默认所有注册用户未激活" 功能,用于在某些特殊场景下进行手动激活 -新增:ProductManager 新增 renderProductOptions() 方法,用于在购物车显示产品扩展信息 -新增:DFAUtil 新增 printDFAMatches() 方法,用于打印匹配的非法内容 -新增:当产品购买完成时,新增发票的申请功能 -新增:OrderManager 新增 registerAdminOrderDetailRender 和 registerUCenterOrderDetailRender 方法,用于自定义订单详情的页面显示 -优化:升级 Jboot 到 3.0.1 最新版 -优化:对 DFAUtil 的 init 进行优化,让其在 App 启动的时候进行 init,否则初次使用的时候会有 "卡顿" 现象 -优化:对 API 和 数据提交 等功能做若干个安全优化 -优化:对 ProductInfoQuerier 进行重构,更加方便的对产品信息进行查询 -优化:对 WechatAuthorizationController 进行重构,使之更加简洁 -优化:对 ArticleServiceProvider 使用 Jboot 3.x 的新 API 进行优化 -优化:删除 deleteByIds(Object... ids) 方法,使用 batchDeleteByIds(Object... ids) 进行代替 -优化:优化产品详情页的相关样式 -优化:对 JPress 的 sql 对索引、字段大小等进行优化 -优化:对 JPressOptions 进行优化,新增若干可以设置默认数据的方法 -优化:对提现功能生成流水的进行事务控制 -修复:注册时,当验证码验证错误的时候提示的内容有误的问题 -修复:微信回复当设置的图片无法上传时,继续发送图片导致异常的问题 -修复:在二级目录下,模板无法正确显示 shortcut icon 的问题 -修复:批量删除产品的时候,无法删除产品图片关联表内容的问题 -修复:添加产品到购物车时,购物车的产品数量可能不正确的问题 -修复:订单详情页里的分销用户显示不正确的问题 -修复:_AttachmentController 在某些极端的情况下可能会出现 NPE 的问题 -修复:修改jcseg分词模式,解决启用lucene后 文章添加图片或者链接保存报错的问题,感谢 @tanghaiyuan -修复:当开启用户提现功能,提现手续费设置后不显示的问题 -修复:当用户提现时,生成的提现流水不正确的问题 -修复:修复提现的余额判断逻辑错误的问题,感谢 @jializh123 -修复:在手机版下,无法进行余额充值和加入会员的问题 -修复:在手机版下,购物车的结算按钮错位,无法进行正常流程下单的问题 - - - -jpress v3.0.6: -修复:在某些情况下订单的商品类型错误的问题 -修复:微信个人收款和支付宝个人收款在某些情况下无法显示二维码的问题 -修复:当送货信息为空的时候,快递信息异常的问题 -修复:购物车进行全选所有商品时,可能会弹出没有选择任何内容的错误提示 -优化:重命名 findByProductTablendProductId() 为 findByProductTypeAndProductId() -优化:更新 sql 脚本的字段说明 -优化:在浏览器双击复制产品标题,订单号码,多了空格,导致查询不出来 -优化:优化用户订单列表进行发货操作的时候,对页面进行刷新 - - - -jpress v3.0.5: -修复:模板卸载的时候可能无法删除所有已安装的模板文件的问题 -修复:修复当文章的分类修改的时候,缓存无法及时更新的问题 -修复:在编译的时候由于Jcseg版本不一致可能存在冲突的问题 -修复:JPress 在二级目录下进行安装的时候,无法正确访问 install 进行安装的问题 -优化:当用户被冻结或者未激活的时候无法上传文件 -优化:修改 lucene 的索引目录,防止文章和产品可能存在索引冲突 -优化:升级 jcseg 的版本到 v2.6 最新版本 -优化:升级 es client 到最新版本 - - - -jpress v3.0.4: -修复:在微信浏览器下无法在线充值和会员支付的问题 -修复:在Android手机下,通过微信浏览器进行支付有时无法唤起支付确认对话框的问题 -修复:JPress 部署在二级目录下可能导致某些图片和样式无法显示的问题 -优化:微信通过 JSAPI 进行支付的时候,当出现错误给出明确的错误提示 -优化:删除一些无用的代码或者注释的代码段 -优化:在手机浏览器下访问用户中心可能会导致某些DIV错位的问题 - - - -jpress v3.0.3: -修复:修复插件在线升级、停止和重启可能在某些情况下出现无法启动的问题 -修复:修复使用微信支付在微信浏览器下无法正确支付的问题 -修复:当已经生成订单的购物车再次发起时错处的问题 -优化:优化自带的模板样式以及评论组件等 -优化:优化页面评论的一些js验证问题 -优化:优化checkout在手机浏览器下html错位的问题 -优化:在支付页面手机浏览器下html错位的问题 -优化:在手机浏览器下,用户中心订单和投稿html错位的问题 - - - -jpress v3.0.2: -新增:新增基于 DFA 算法的垃圾内容评论、投稿过滤 -新增:#hasMember 和 #hasAnyMember 的模板标签 -修复:修复 hasMember 和 hasAnyMember 指令无法使用的问题 -修复:优惠劵大于 订单金额会导致 负数的问题,感谢 @orangehs - - - -jpress v3.0.1: -新增:OSS 同步删除文件的后台配置,感谢 @haicuan139 -新增:收货地址的 API 接口,感谢 @haicuan139 -新增:用户中心新增优惠券查看的功能,感谢 @haicuan139 -新增:后台的用户详情现在优惠券的查看及分配的功能,感谢 @haicuan139 -新增:支付台新增可以在支付的时候可以选择自己的优惠券的功能,感谢 @haicuan139 -新增:文章的 API 新增文章搜索的功能,感谢 @haicuan139 -新增:产品模块新增产品搜索的功能,感谢 @haicuan139 -新增:hasPermission(String actionKey) 的模板方法 -优化:当 JPress 渲染的模板文件不存在时,给出更加明确的错误提示。 -优化:如果用户第一次添加收货地址,设定为默认地址,感谢 @haicuan139 -优化:增加了收货地址的空字段验证,感谢 @haicuan139 -优化:后台管理的用户资料菜单增加权限判断,可通过权限配置来控制菜单的显示,感谢 @haicuan139 -优化:对 hasPermission 指令错误提示优化 -优化:对模板方法的相关类全部修改为 Function 结尾 -修复:修复后台的模板设置功能,无法正确渲染模板的图片的问题 -修复:修复微信支付不能出现404错误的问题 -修复:修复了新增地址时设置默认地址不生效的问题,感谢 @haicuan139 -修复:修复后台的用户订单列表无法对其搜索的bug,感谢 @haicuan139 - - - -jpress v3.0.0: -新增:新增 hasMember() 和 hasAnyMember() 两个模板指令,更加方便的对会员内容进行控制 -优化:强化对可能产生 XSS 漏洞的 Model 防护 -优化:优化模板方法 maxLength() 的逻辑 -优化:优化后台上传文件时,更加友好的显示上传进度 -优化:升级 JPress 的所有版本未 3.0 -优化:优化 后台编辑器 切换的文字内容,使之更加直观 -优化:升级 JPress 所有 maven 依赖的到最新版本 -优化:优化订单列表的不同状态显示不同的颜色,使之更加直观 -优化:JPress 在安装或者重新安装时,当出现错误时给出更明确的错误提示 -优化:默认情况下,JPress 会开启评论功能,除非手动关闭 -修复:修复后台 CKEditor 和 Markdown 编辑器无法切换的问题 -修复:修复用户中心文章投稿可能产生恶意投稿的问题 -修复:修复 JPress 启动时可能出现的目录无法找到的问题 -修复:修复 后台无法对产品评论进行回复和编辑的问题 -修复:修复 产品评论回复后该产品的被回复数量数据不正确的问题 -修复:修复 产品标签点击后会显示 404 的问题 -修复:倘若插件有复合主键的 Model,无法对其进行正确操作的问题 - - - -jpress v3.0.0-rc.3: -优化:文章分类归属后,再次修改分类内容会导致文章分类更新不及时的问题 -优化:在会员支付、充值等页面调整为 Ajax 提交和验证 -优化:优化 jpress 初始化的 sql,对某些索引进行优化 和 文字说明 -优化:优化后台模板编辑的文件排序 -优化:对 OrderManager 进行重构,方便订单不同逻辑的解耦 -优化:用户收入类型新增优惠码推广收入 -优化:升级 JFinal、Undertow、Jboot 到最新版本 -修复:商品标签修改后缓存不更新的问题 -修复:支付页面未配置微信转账支付时可能会报错的问题 -修复:修复优惠券后台创建后不能再次分配的问题 -修复:修复模板由于打包不规范可能会导致后台模板无法显示的问题 -修复:修复后台查看用户流水情况显示的是登录用户流水的问题 - - - -jpress v3.0.0-rc.2: -新增:新增获取商品的 API -新增:商品的smartField功能,感谢 @喜欢吃豆包 -新增:新增产品标签 @categoryProducts、@nextProduct、@previousProduct、@relevantProducts -优化:优化默认的文章评论、商品评论和页面评论 UI 样式问题 -优化:完善当对订单进行支付,再次支付直接跳转到成功页面 -优化:优化产品后台对产品编辑是填写的产品视频以及视频封面图的问题 -优化:优化当有多个订单项时,订单的商品描述的构建逻辑 -优化:优化 JsoupUtil 对 a 标签的过滤逻辑 -优化:优化 文章评论、页面评论 和 商品评论 的验证码判断逻辑 -优化:优化 当未登录用户 对产品进行操作时的登录逻辑 -优化:后台对产品删除时,同时删除其关联的图片列表设置 -修复:当用户未登录时,直接购买商品的 js 错误问题 -修复:修复 UTM 拦截器里,当微信小程序传入 JWt 时无法正确获取用户的问题 -修复:CSRF 拦截器可能会对 do 开头的单词方法进行拦截的问题 -修复:修复当使用支付宝进行支付时,当产品标题有空格会造成签名错误的问题 -修复:商品访问的真实数量不更新的问题,感谢 @喜欢吃豆包 -修复:获取相似商品api接口sql错误,感谢 @喜欢吃豆包 -修复:SmartField 对复选框、单选框和下拉菜单设置的文本内容不起作用的问题 -修复:修复后台商品的产品列表无法添加的问题 -修复:商品的标签和分类 不可删除的问题,感谢 @喜欢吃豆包 -修复:订单筛选不可用的问题,感谢 @喜欢吃豆包 -修复:calmlog 的商品详情模板的推荐商品代码逻辑问题 -修复:产品 和 文章的分类、标签再次更新时由于缓存原因不能及时更新的问题 -修复:支付台页面的支付类型不能自动选择的问题 -修复:非用户中心的模板页面无法获取购物车信息的问题 -修复:后台对附件删除时无法对物理文件删除的问题 - - - -jpress v3.0.0-rc.1: -新增:后台新增用户的金额显示能力 -新增:新增用户标签的功能 -新增:新增会员的购买记录功能 -新增:新增用户提现的功能 -新增:新增一键发送邮件、短信、模板消息到用户的功能 -新增:新增全局标签 #(CDN) 用于读取后台配置 CDN 的功能 -优化:新的后台登录背景图 -优化:优化 JPressOptions 大小写可能和 Mysql 不一致的问题 -优化:优化 后台支付宝支付配置的显示问题 -优化:优化支付宝和微信支付扫码成功时,自动跳转的逻辑判断 -优化:完善微信支付后台的文字提示内容 -优化:优化产品保存成功时的文字提示 -优化:优化订单详情的快递信息显示错位的问题 -优化:删除用户中心对评论的再次编辑功能 -优化:后台在不配置运行上传附件大小的情况下,默认上传最大附件为 10 MB -修复:微信扫码支付签名错误的问题 -修复:修复微信充值支余额付入账可能错误的问题 -修复:修复会员组编辑出错的问题 -修复:修复由于缓存问题导致后台更新产品时,前台没有发生变化的问题 -修复:后台重新对产品编辑可能出错的问题 -修复:修复后台对文件上传大小填写0时,不是允许上传任意大小的问题 -修复:修复 index 为 Action 时,肯能权限无法访问的问题 - - - -jpress v3.0.0-beta.2: -新增:支付宝设置新增扫码支付的开关功能 -新增:新增支付宝支付的 wap 浏览器唤起支付宝 APP 支付的功能 -新增:订单新增是否是虚拟产品和是否支持退款的支持 -新增:新增有新订单时,可以通过邮件、手机短信 和 微信公众号通知管理员的功能 -新增:新增 GetOpenIdAddon 微信运营插件 -新增:新增 后台可以填写管理员邮箱、手机号和微信 openId 的功能 -新增:新增后台 邮件配置时,可以进行一键测试的功能 -新增:新增可以对页面进行评论额功能 -优化:优化文章评论的邮件发送配置功能 -优化:微信菜单设置的选择功能和错误提示 -优化:优化后台支付宝收款账号的帮助文字内容。 -优化:优化文章和产品评论的验证码显示 -优化:重构 PayController 的相关代码 -优化:重构 JPress 的安装和升级流程 -优化:优化用户支付成功时,能顺利进入用户所需模块 -优化:重构支付成功时,对 payment 的通知流程 -优化:重构 Sitemap 模块,减少文章的查询功能,提供效率 -优化:重构 物流选择模块,可以通过插件等其他方式新增物流查询方式 -优化:优化用户登录的钉钉第三方支付帮助文字错误的问题 -优化:优化模板的指令和layout,让4套自带模板统一 -优化:优化后台在删除数据的时候,给出确认对话框 -优化:升级 Jboot 到 v2.2.8 最新版本,并对 JPress 线程池的创建进行重构 -修复:修复通过用户和类型去获取OpenId可能出错的问题 -修复:修复优惠券编辑时可能出错的问题 -修复:修复优惠券无法删除的问题 -修复:修复支付宝充值时,当有小数点充值不到账的bug -修复:修复支付宝和微信充值时,流水信息不正确的问题 -修复:修复财务基础设置里填写的域名无法显示的问题 -修复:修复支付宝和微信扫码支付时,无法正常刷新的问题 -修复:用户进行分销时,当订单延迟结束时,分销金额无法到账的问题 - - - -jpress v3.0.0-beta.1: -新增:JPress v2 平滑升级到 v3 的功能 -新增:微信回复的默认回复功能支持回复任何的数据类型 -新增:后台订单详情详细显示每个订单项的分销人及分销金额 -新增:文章新增可以自定义文章发布时间的功能 -新增:#articles 指令新增可以传入多个 flag 的功能 -修复:defaultArticleCommentItem 和 defaultProductCommentItem 在关闭评论时任然显示回复按钮的问题 -修复:产品和文章评论时,当有父级评论时无法正确显示的问题 -修复:当开启阿里云的 OpenSearcher 或 Es,但是填写的配置不正确时,无法保存文章的问题 -修复:新增当产生分销时,分享着无法正确获取收入的问题 -修复:JsoupUtil.getText() 会对 escape 内容进行转换的问题 -修复:优惠券编辑时可能出错的问题 -修复:微信在线支付和支付宝在线支付无法正确显示二维码的问题 -优化:defaultArticleCommentItem 和 defaultProductCommentItem 的回复样式 -优化:优化微信回复的 placeholder 的内容 -优化:优化选择图片组件默认图片以及UI间距等问题 -优化:jp-image-browser class 修改为 btn-image-browser -优化:删除 payment 以及 userOrder 表的无用字段 -优化:修改 isLogineUserModel() 和 notLogineUserModel() 为 isLoginedUserModel() 和 notLoginedUserModel() -优化:升级 Jboot 到 v2.2.7 最新版本 - - - -jpress v3.0.0-alpha.2: -新增:新增后台产品的编辑页面,添加会员价的功能 -新增:购物车以及结算台新增会员价的展示功能 -新增:后台新增管理对会员的修改、删除和续期等功能 -优化:购物车选中产品的代码,使之更加容易阅读 -优化:继续优化和完善 Mysql 数据库的索引构建 -优化:defaultArticleCommentPage 和 defaultProductCommentPage,在关闭评论的时候不再显示评论的输入框 -优化:优化插件 Handler 管理器 AddonHandlerManager 和 AddonHandlerProcesser 的逻辑 -优化:优化 PaymentManager,减少监听器 isPaySuccess 的判断 -优化:微信后台保存菜单时,提示用户必须输入项 -优化:微信关键字保存时,添加是否已经存在关键字的友好提示 -优化:优化模板管理器 TemplateManger 以及 Template 的相关代码 -优化:重构 checkOwner ,修改为 isLogineUserModel 和 notLogineUserModel -修复:商品分类默认页面配置错误,感谢 @喜欢吃豆包 -修复:优惠券编辑时 类型和验证类型默认值不显示问题,感谢 @喜欢吃豆包 -修复:用户中心的加入会员列表可能出现错误的问题 -修复:Windows系统下模板路径肯能出错的问题 - - - -jpress v3.0.0-alpha.1: -第一个 3.0 版本 - +jpress v3.2.3: +新增:新增用户绑定账号后,取消绑定的功能 +新增:尝试性支持 jdk11 ~ jdk14 +修复:快递100查询时因签名未转大写,造成签名错误而无法正常显示快递信息问题。感谢 @lixuanqun +修复:下载的附件目录不规范的问题,感谢 @Retire +优化:优化 OauthConnector,支持可以自由配置回调域名 +优化:优化 违法关键字 词库 + + + +jpress v3.2.2: +优化:JPress 的安装和升级流程 +优化:重构第三方登录的授权流程 +优化:优化产品的相关指令和注释 +修复:使用 QQ 第三方登录的时候无法正常登录的问题 +修复:正确设置微信小程序、第三方登录等的首次用户状态 +修复:当产品详情页引用 product.js 但是未启用 Swiper 的时候出错的问题 +修复:checkout 页面无法正确删除产品的问题 +修复:JPress 低版本升级到最新版本是,倘若最后一步不填写管理员账号密码会出错的问题 + + + +jpress v3.2.1: +新增:模板预览功能,前端可以通过 url 访问指定已经安装的模板 +优化:升级 ckeditor 到最新版本,以支持 word 的复制粘贴功能 +优化:通过 QQ 进行第三方登录时,发生错误提示不明显的问题 +修复:分销用户无法正确获取分销金额的问题 +修复:ArticleService.findListByCategoryId() 的 count 参数不起作用的问题 +修复:通过 paypal 进行支付发生错误的问题 +修复:加购物车返回的 Json 内容不正确的问题,感谢 @一座城你说你不懂 +修复:通过 Github 第三方登录无法获取正确的用户数据的问题 + + + +jpress v3.2.0: +新增:添加一个全新的插件:留言插件,方便网站使用其增强 "留言" 功能,同时方便新手作为一个参考去开发自己的插件,感谢作者 @安杰 +新增:可以通过 URL 直接访问模板页面的功能,假设存在模板 abc.html,增可以直接通过 http://domain/abc 去访问。 +新增:默认模板 calmlog 新增文章搜索功能 +新增:产品详情页新增 URL 分享按钮,当产品启用分销时,分销的 URL 可以获得相应的佣金。 +优化:重构 TemplateManager,使其代码更加简洁 +优化:优化 #CategoriesDirective 指令,防止在产品页面使用时出现类型转换错误的问题 +优化:对 BaseProductInfoQuerier 进行重构,方便在开发插件的时候可以获取更多的信息 +优化:删除 ArticleServiceProvider 中多余的不必要的注解 +优化:对 AddonControllerManager 进行优化,插件的 Controller 的 viewPath 不用必须为 "/" 的问题 +优化:对 微信支付的后台配置添加相应的文字说明,方便使用者更加清晰的去使用 +优化:对 订单和支付等内容进行 "固化",不允许自己去支付别人的订单。 +修复:当产品启用 Lucene 搜索引擎后,无法搜索其内容的问题 +修复:当产品更新的时候,缓存无法及时清空的问题 +修复:当产品和文章同时开启 ElasticSearch 搜索引擎的时候,会出现索引覆盖的问题 +修复:对用户进行删除的时候,没有删除用户的 OpenId,导致该用户每次访问都会创建新的用户的问题 +文档:添加 JPress 升级的相关文档 + + + +jpress v3.1.1: +新增:订单超时的时间设置功能,超时订单自动被关闭 +新增:新增产品分类的标签 #productCategoryList,用于读取产品分类内容 +优化:优化订单列表的文字样式以及发货按钮的显示逻辑 +优化:移除 AdminOrderDetailPgeRender 和 UCenterOrderDetailPageRender 的配置支持 +优化:优化 install.sh ,在某些时候无法正常安装的问题 +优化:优化 docker-compose.yml ,升级 mysql image 到 5.7 +优化:用户推出方法 doLogout() 修改为 logout() +优化:优化插件模块,在某些极端情况下出现无法删除插件内容的问题 +优化:升级jboot、fastjson、jcseg等相关依赖到最新版本 +修复:购买产品时,默认地址不正确的问题 +修复:对未支付订单重新支付时,无法选择新地址的问题 +修复:修复代码生成器生成的代码内容编辑的 URL 路径错误的问题,感谢 @安杰 +修复:代码生成器生成的代码中,进行批量删除时出现404的问题,感谢 @安杰 + + + +jpress v3.1.0: +新增:新增 GlobalInterceptor 注解,插件拦截器必须通过此声明才能设置为全局拦截器 +新增:AddonUtil 新增 addSharedFunction() 和 removeSharedFunction() 方法,用于对插件共享模板的新增和移除 +新增:AddonUtil 新增 getViewPath() 方法,用于获取插件的文件路径 +新增:用户注册新增 "默认所有注册用户未激活" 功能,用于在某些特殊场景下进行手动激活 +新增:ProductManager 新增 renderProductOptions() 方法,用于在购物车显示产品扩展信息 +新增:DFAUtil 新增 printDFAMatches() 方法,用于打印匹配的非法内容 +新增:当产品购买完成时,新增发票的申请功能 +新增:OrderManager 新增 registerAdminOrderDetailRender 和 registerUCenterOrderDetailRender 方法,用于自定义订单详情的页面显示 +优化:升级 Jboot 到 3.0.1 最新版 +优化:对 DFAUtil 的 init 进行优化,让其在 App 启动的时候进行 init,否则初次使用的时候会有 "卡顿" 现象 +优化:对 API 和 数据提交 等功能做若干个安全优化 +优化:对 ProductInfoQuerier 进行重构,更加方便的对产品信息进行查询 +优化:对 WechatAuthorizationController 进行重构,使之更加简洁 +优化:对 ArticleServiceProvider 使用 Jboot 3.x 的新 API 进行优化 +优化:删除 deleteByIds(Object... ids) 方法,使用 batchDeleteByIds(Object... ids) 进行代替 +优化:优化产品详情页的相关样式 +优化:对 JPress 的 sql 对索引、字段大小等进行优化 +优化:对 JPressOptions 进行优化,新增若干可以设置默认数据的方法 +优化:对提现功能生成流水的进行事务控制 +修复:注册时,当验证码验证错误的时候提示的内容有误的问题 +修复:微信回复当设置的图片无法上传时,继续发送图片导致异常的问题 +修复:在二级目录下,模板无法正确显示 shortcut icon 的问题 +修复:批量删除产品的时候,无法删除产品图片关联表内容的问题 +修复:添加产品到购物车时,购物车的产品数量可能不正确的问题 +修复:订单详情页里的分销用户显示不正确的问题 +修复:_AttachmentController 在某些极端的情况下可能会出现 NPE 的问题 +修复:修改jcseg分词模式,解决启用lucene后 文章添加图片或者链接保存报错的问题,感谢 @tanghaiyuan +修复:当开启用户提现功能,提现手续费设置后不显示的问题 +修复:当用户提现时,生成的提现流水不正确的问题 +修复:修复提现的余额判断逻辑错误的问题,感谢 @jializh123 +修复:在手机版下,无法进行余额充值和加入会员的问题 +修复:在手机版下,购物车的结算按钮错位,无法进行正常流程下单的问题 + + + +jpress v3.0.6: +修复:在某些情况下订单的商品类型错误的问题 +修复:微信个人收款和支付宝个人收款在某些情况下无法显示二维码的问题 +修复:当送货信息为空的时候,快递信息异常的问题 +修复:购物车进行全选所有商品时,可能会弹出没有选择任何内容的错误提示 +优化:重命名 findByProductTablendProductId() 为 findByProductTypeAndProductId() +优化:更新 sql 脚本的字段说明 +优化:在浏览器双击复制产品标题,订单号码,多了空格,导致查询不出来 +优化:优化用户订单列表进行发货操作的时候,对页面进行刷新 + + + +jpress v3.0.5: +修复:模板卸载的时候可能无法删除所有已安装的模板文件的问题 +修复:修复当文章的分类修改的时候,缓存无法及时更新的问题 +修复:在编译的时候由于Jcseg版本不一致可能存在冲突的问题 +修复:JPress 在二级目录下进行安装的时候,无法正确访问 install 进行安装的问题 +优化:当用户被冻结或者未激活的时候无法上传文件 +优化:修改 lucene 的索引目录,防止文章和产品可能存在索引冲突 +优化:升级 jcseg 的版本到 v2.6 最新版本 +优化:升级 es client 到最新版本 + + + +jpress v3.0.4: +修复:在微信浏览器下无法在线充值和会员支付的问题 +修复:在Android手机下,通过微信浏览器进行支付有时无法唤起支付确认对话框的问题 +修复:JPress 部署在二级目录下可能导致某些图片和样式无法显示的问题 +优化:微信通过 JSAPI 进行支付的时候,当出现错误给出明确的错误提示 +优化:删除一些无用的代码或者注释的代码段 +优化:在手机浏览器下访问用户中心可能会导致某些DIV错位的问题 + + + +jpress v3.0.3: +修复:修复插件在线升级、停止和重启可能在某些情况下出现无法启动的问题 +修复:修复使用微信支付在微信浏览器下无法正确支付的问题 +修复:当已经生成订单的购物车再次发起时错处的问题 +优化:优化自带的模板样式以及评论组件等 +优化:优化页面评论的一些js验证问题 +优化:优化checkout在手机浏览器下html错位的问题 +优化:在支付页面手机浏览器下html错位的问题 +优化:在手机浏览器下,用户中心订单和投稿html错位的问题 + + + +jpress v3.0.2: +新增:新增基于 DFA 算法的垃圾内容评论、投稿过滤 +新增:#hasMember 和 #hasAnyMember 的模板标签 +修复:修复 hasMember 和 hasAnyMember 指令无法使用的问题 +修复:优惠劵大于 订单金额会导致 负数的问题,感谢 @orangehs + + + +jpress v3.0.1: +新增:OSS 同步删除文件的后台配置,感谢 @haicuan139 +新增:收货地址的 API 接口,感谢 @haicuan139 +新增:用户中心新增优惠券查看的功能,感谢 @haicuan139 +新增:后台的用户详情现在优惠券的查看及分配的功能,感谢 @haicuan139 +新增:支付台新增可以在支付的时候可以选择自己的优惠券的功能,感谢 @haicuan139 +新增:文章的 API 新增文章搜索的功能,感谢 @haicuan139 +新增:产品模块新增产品搜索的功能,感谢 @haicuan139 +新增:hasPermission(String actionKey) 的模板方法 +优化:当 JPress 渲染的模板文件不存在时,给出更加明确的错误提示。 +优化:如果用户第一次添加收货地址,设定为默认地址,感谢 @haicuan139 +优化:增加了收货地址的空字段验证,感谢 @haicuan139 +优化:后台管理的用户资料菜单增加权限判断,可通过权限配置来控制菜单的显示,感谢 @haicuan139 +优化:对 hasPermission 指令错误提示优化 +优化:对模板方法的相关类全部修改为 Function 结尾 +修复:修复后台的模板设置功能,无法正确渲染模板的图片的问题 +修复:修复微信支付不能出现404错误的问题 +修复:修复了新增地址时设置默认地址不生效的问题,感谢 @haicuan139 +修复:修复后台的用户订单列表无法对其搜索的bug,感谢 @haicuan139 + + + +jpress v3.0.0: +新增:新增 hasMember() 和 hasAnyMember() 两个模板指令,更加方便的对会员内容进行控制 +优化:强化对可能产生 XSS 漏洞的 Model 防护 +优化:优化模板方法 maxLength() 的逻辑 +优化:优化后台上传文件时,更加友好的显示上传进度 +优化:升级 JPress 的所有版本未 3.0 +优化:优化 后台编辑器 切换的文字内容,使之更加直观 +优化:升级 JPress 所有 maven 依赖的到最新版本 +优化:优化订单列表的不同状态显示不同的颜色,使之更加直观 +优化:JPress 在安装或者重新安装时,当出现错误时给出更明确的错误提示 +优化:默认情况下,JPress 会开启评论功能,除非手动关闭 +修复:修复后台 CKEditor 和 Markdown 编辑器无法切换的问题 +修复:修复用户中心文章投稿可能产生恶意投稿的问题 +修复:修复 JPress 启动时可能出现的目录无法找到的问题 +修复:修复 后台无法对产品评论进行回复和编辑的问题 +修复:修复 产品评论回复后该产品的被回复数量数据不正确的问题 +修复:修复 产品标签点击后会显示 404 的问题 +修复:倘若插件有复合主键的 Model,无法对其进行正确操作的问题 + + + +jpress v3.0.0-rc.3: +优化:文章分类归属后,再次修改分类内容会导致文章分类更新不及时的问题 +优化:在会员支付、充值等页面调整为 Ajax 提交和验证 +优化:优化 jpress 初始化的 sql,对某些索引进行优化 和 文字说明 +优化:优化后台模板编辑的文件排序 +优化:对 OrderManager 进行重构,方便订单不同逻辑的解耦 +优化:用户收入类型新增优惠码推广收入 +优化:升级 JFinal、Undertow、Jboot 到最新版本 +修复:商品标签修改后缓存不更新的问题 +修复:支付页面未配置微信转账支付时可能会报错的问题 +修复:修复优惠券后台创建后不能再次分配的问题 +修复:修复模板由于打包不规范可能会导致后台模板无法显示的问题 +修复:修复后台查看用户流水情况显示的是登录用户流水的问题 + + + +jpress v3.0.0-rc.2: +新增:新增获取商品的 API +新增:商品的smartField功能,感谢 @喜欢吃豆包 +新增:新增产品标签 @categoryProducts、@nextProduct、@previousProduct、@relevantProducts +优化:优化默认的文章评论、商品评论和页面评论 UI 样式问题 +优化:完善当对订单进行支付,再次支付直接跳转到成功页面 +优化:优化产品后台对产品编辑是填写的产品视频以及视频封面图的问题 +优化:优化当有多个订单项时,订单的商品描述的构建逻辑 +优化:优化 JsoupUtil 对 a 标签的过滤逻辑 +优化:优化 文章评论、页面评论 和 商品评论 的验证码判断逻辑 +优化:优化 当未登录用户 对产品进行操作时的登录逻辑 +优化:后台对产品删除时,同时删除其关联的图片列表设置 +修复:当用户未登录时,直接购买商品的 js 错误问题 +修复:修复 UTM 拦截器里,当微信小程序传入 JWt 时无法正确获取用户的问题 +修复:CSRF 拦截器可能会对 do 开头的单词方法进行拦截的问题 +修复:修复当使用支付宝进行支付时,当产品标题有空格会造成签名错误的问题 +修复:商品访问的真实数量不更新的问题,感谢 @喜欢吃豆包 +修复:获取相似商品api接口sql错误,感谢 @喜欢吃豆包 +修复:SmartField 对复选框、单选框和下拉菜单设置的文本内容不起作用的问题 +修复:修复后台商品的产品列表无法添加的问题 +修复:商品的标签和分类 不可删除的问题,感谢 @喜欢吃豆包 +修复:订单筛选不可用的问题,感谢 @喜欢吃豆包 +修复:calmlog 的商品详情模板的推荐商品代码逻辑问题 +修复:产品 和 文章的分类、标签再次更新时由于缓存原因不能及时更新的问题 +修复:支付台页面的支付类型不能自动选择的问题 +修复:非用户中心的模板页面无法获取购物车信息的问题 +修复:后台对附件删除时无法对物理文件删除的问题 + + + +jpress v3.0.0-rc.1: +新增:后台新增用户的金额显示能力 +新增:新增用户标签的功能 +新增:新增会员的购买记录功能 +新增:新增用户提现的功能 +新增:新增一键发送邮件、短信、模板消息到用户的功能 +新增:新增全局标签 #(CDN) 用于读取后台配置 CDN 的功能 +优化:新的后台登录背景图 +优化:优化 JPressOptions 大小写可能和 Mysql 不一致的问题 +优化:优化 后台支付宝支付配置的显示问题 +优化:优化支付宝和微信支付扫码成功时,自动跳转的逻辑判断 +优化:完善微信支付后台的文字提示内容 +优化:优化产品保存成功时的文字提示 +优化:优化订单详情的快递信息显示错位的问题 +优化:删除用户中心对评论的再次编辑功能 +优化:后台在不配置运行上传附件大小的情况下,默认上传最大附件为 10 MB +修复:微信扫码支付签名错误的问题 +修复:修复微信充值支余额付入账可能错误的问题 +修复:修复会员组编辑出错的问题 +修复:修复由于缓存问题导致后台更新产品时,前台没有发生变化的问题 +修复:后台重新对产品编辑可能出错的问题 +修复:修复后台对文件上传大小填写0时,不是允许上传任意大小的问题 +修复:修复 index 为 Action 时,肯能权限无法访问的问题 + + + +jpress v3.0.0-beta.2: +新增:支付宝设置新增扫码支付的开关功能 +新增:新增支付宝支付的 wap 浏览器唤起支付宝 APP 支付的功能 +新增:订单新增是否是虚拟产品和是否支持退款的支持 +新增:新增有新订单时,可以通过邮件、手机短信 和 微信公众号通知管理员的功能 +新增:新增 GetOpenIdAddon 微信运营插件 +新增:新增 后台可以填写管理员邮箱、手机号和微信 openId 的功能 +新增:新增后台 邮件配置时,可以进行一键测试的功能 +新增:新增可以对页面进行评论额功能 +优化:优化文章评论的邮件发送配置功能 +优化:微信菜单设置的选择功能和错误提示 +优化:优化后台支付宝收款账号的帮助文字内容。 +优化:优化文章和产品评论的验证码显示 +优化:重构 PayController 的相关代码 +优化:重构 JPress 的安装和升级流程 +优化:优化用户支付成功时,能顺利进入用户所需模块 +优化:重构支付成功时,对 payment 的通知流程 +优化:重构 Sitemap 模块,减少文章的查询功能,提供效率 +优化:重构 物流选择模块,可以通过插件等其他方式新增物流查询方式 +优化:优化用户登录的钉钉第三方支付帮助文字错误的问题 +优化:优化模板的指令和layout,让4套自带模板统一 +优化:优化后台在删除数据的时候,给出确认对话框 +优化:升级 Jboot 到 v2.2.8 最新版本,并对 JPress 线程池的创建进行重构 +修复:修复通过用户和类型去获取OpenId可能出错的问题 +修复:修复优惠券编辑时可能出错的问题 +修复:修复优惠券无法删除的问题 +修复:修复支付宝充值时,当有小数点充值不到账的bug +修复:修复支付宝和微信充值时,流水信息不正确的问题 +修复:修复财务基础设置里填写的域名无法显示的问题 +修复:修复支付宝和微信扫码支付时,无法正常刷新的问题 +修复:用户进行分销时,当订单延迟结束时,分销金额无法到账的问题 + + + +jpress v3.0.0-beta.1: +新增:JPress v2 平滑升级到 v3 的功能 +新增:微信回复的默认回复功能支持回复任何的数据类型 +新增:后台订单详情详细显示每个订单项的分销人及分销金额 +新增:文章新增可以自定义文章发布时间的功能 +新增:#articles 指令新增可以传入多个 flag 的功能 +修复:defaultArticleCommentItem 和 defaultProductCommentItem 在关闭评论时任然显示回复按钮的问题 +修复:产品和文章评论时,当有父级评论时无法正确显示的问题 +修复:当开启阿里云的 OpenSearcher 或 Es,但是填写的配置不正确时,无法保存文章的问题 +修复:新增当产生分销时,分享着无法正确获取收入的问题 +修复:JsoupUtil.getText() 会对 escape 内容进行转换的问题 +修复:优惠券编辑时可能出错的问题 +修复:微信在线支付和支付宝在线支付无法正确显示二维码的问题 +优化:defaultArticleCommentItem 和 defaultProductCommentItem 的回复样式 +优化:优化微信回复的 placeholder 的内容 +优化:优化选择图片组件默认图片以及UI间距等问题 +优化:jp-image-browser class 修改为 btn-image-browser +优化:删除 payment 以及 userOrder 表的无用字段 +优化:修改 isLogineUserModel() 和 notLogineUserModel() 为 isLoginedUserModel() 和 notLoginedUserModel() +优化:升级 Jboot 到 v2.2.7 最新版本 + + + +jpress v3.0.0-alpha.2: +新增:新增后台产品的编辑页面,添加会员价的功能 +新增:购物车以及结算台新增会员价的展示功能 +新增:后台新增管理对会员的修改、删除和续期等功能 +优化:购物车选中产品的代码,使之更加容易阅读 +优化:继续优化和完善 Mysql 数据库的索引构建 +优化:defaultArticleCommentPage 和 defaultProductCommentPage,在关闭评论的时候不再显示评论的输入框 +优化:优化插件 Handler 管理器 AddonHandlerManager 和 AddonHandlerProcesser 的逻辑 +优化:优化 PaymentManager,减少监听器 isPaySuccess 的判断 +优化:微信后台保存菜单时,提示用户必须输入项 +优化:微信关键字保存时,添加是否已经存在关键字的友好提示 +优化:优化模板管理器 TemplateManger 以及 Template 的相关代码 +优化:重构 checkOwner ,修改为 isLogineUserModel 和 notLogineUserModel +修复:商品分类默认页面配置错误,感谢 @喜欢吃豆包 +修复:优惠券编辑时 类型和验证类型默认值不显示问题,感谢 @喜欢吃豆包 +修复:用户中心的加入会员列表可能出现错误的问题 +修复:Windows系统下模板路径肯能出错的问题 + + + +jpress v3.0.0-alpha.1: +第一个 3.0 版本 + diff --git a/codegen/pom.xml b/codegen/pom.xml index e1132a468d3cdb59da39b73cd477be9b3bcf7bb8..6172cc9cf3662abfffd02abb2d4920a508950539 100644 --- a/codegen/pom.xml +++ b/codegen/pom.xml @@ -1,56 +1,56 @@ - - - - io.jpress - parent - 3.0 - - 4.0.0 - - io.jpress - codegen - - - 1.8 - 1.8 - - - - - - - io.jboot - jboot - - - - - - - - src/main/java - - - **/*.jf - - false - - - - src/main/resources - - **/* - - - - *.properties - - - - - - - + + + + io.jpress + parent + 3.0 + + 4.0.0 + + io.jpress + codegen + + + 1.8 + 1.8 + + + + + + + io.jboot + jboot + + + + + + + + src/main/java + + + **/*.jf + + false + + + + src/main/resources + + **/* + + + + *.properties + + + + + + + \ No newline at end of file diff --git a/codegen/src/main/java/io/jpress/codegen/AddonGenerator.java b/codegen/src/main/java/io/jpress/codegen/AddonGenerator.java index ae9c9946c6d8b2dce8d832a4ab89583a8315a8dd..225109f50ce2c56709ccd8204acd0f46fc5f9f8c 100644 --- a/codegen/src/main/java/io/jpress/codegen/AddonGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/AddonGenerator.java @@ -1,136 +1,136 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen; - -import com.jfinal.kit.PathKit; -import com.jfinal.plugin.activerecord.generator.MetaBuilder; -import com.jfinal.plugin.activerecord.generator.TableMeta; -import io.jboot.app.JbootApplication; -import io.jboot.codegen.CodeGenHelpler; -import io.jboot.utils.StrUtil; -import io.jpress.codegen.generator.*; - -import java.util.List; -import java.util.Set; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 根据数据库信息,生成 maven module - * @Package io.jpress.core.code - */ -public class AddonGenerator { - - private String addonName; - private String dbUrl; - private String dbUser; - private String dbPassword; - private String dbTables; - private String optionsTables; - private String modelPackage; - private String servicePackage; - - private String basePath; - - private boolean genUI = false; - - - public AddonGenerator(String addonName, String dbUrl, String dbUser, String dbPassword, String dbTables, String modelPackage, String servicePackage) { - this.addonName = addonName; - this.dbUrl = dbUrl; - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.dbTables = dbTables; - this.modelPackage = modelPackage; - this.servicePackage = servicePackage; - this.basePath = PathKit.getWebRootPath() + "/../jpress-addon-" + addonName; - } - - - public AddonGenerator(String addonName, String dbUrl, String dbUser, String dbPassword, String dbTables, String optionsTables, String modelPackage, String servicePackage) { - this.addonName = addonName; - this.dbUrl = dbUrl; - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.dbTables = dbTables; - this.optionsTables = optionsTables; - this.modelPackage = modelPackage; - this.servicePackage = servicePackage; - this.basePath = PathKit.getWebRootPath() + "/../jpress-addon-" + addonName; - } - - - public boolean isGenUI() { - return genUI; - } - - public AddonGenerator setGenUI(boolean genUI) { - this.genUI = genUI; - return this; - } - - public void gen() { - - genCode(); - - } - - - private void genCode() { - - - JbootApplication.setBootArg("jboot.datasource.url", dbUrl); - JbootApplication.setBootArg("jboot.datasource.user", dbUser); - JbootApplication.setBootArg("jboot.datasource.password", dbPassword); - - String baseModelPackage = modelPackage + ".base"; - - String modelDir = basePath + "/src/main/java/" + modelPackage.replace(".", "/"); - String baseModelDir = basePath + "/src/main/java/" + baseModelPackage.replace(".", "/"); - - System.out.println("start generate... dir:" + modelDir); - - MetaBuilder metaBuilder = CodeGenHelpler.createMetaBuilder(); - metaBuilder.setGenerateRemarks(true); - List tableMetas = metaBuilder.build(); - - Set genTableNames = StrUtil.splitToSet(dbTables, ","); - tableMetas.removeIf(tableMeta -> genTableNames != null && !genTableNames.contains(tableMeta.name.toLowerCase())); - - - new BaseModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); - new ModelGenerator(modelPackage, baseModelPackage, modelDir).generate(tableMetas); - - String apiPath = basePath + "/src/main/java/" + servicePackage.replace(".", "/"); - String providerPath = basePath + "/src/main/java/" + servicePackage.replace(".", "/") + "/provider"; - - new ServiceApiGenerator(servicePackage, modelPackage, apiPath).generate(tableMetas); - new ServiceProviderGenerator(servicePackage, modelPackage, providerPath).generate(tableMetas); - - if (genUI) { - new AddonUIGenerator(basePath, addonName, modelPackage, tableMetas) - .genControllers() - .genEdit() - .genList(); - } - - Set optionsTableNames = StrUtil.splitToSet(optionsTables, ","); - if (optionsTableNames != null && optionsTableNames.size() > 0) { - tableMetas.removeIf(tableMeta -> !optionsTableNames.contains(tableMeta.name.toLowerCase())); - new BaseOptionsModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); - } - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen; + +import com.jfinal.kit.PathKit; +import com.jfinal.plugin.activerecord.generator.MetaBuilder; +import com.jfinal.plugin.activerecord.generator.TableMeta; +import io.jboot.app.JbootApplication; +import io.jboot.codegen.CodeGenHelpler; +import io.jboot.utils.StrUtil; +import io.jpress.codegen.generator.*; + +import java.util.List; +import java.util.Set; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 根据数据库信息,生成 maven module + * @Package io.jpress.core.code + */ +public class AddonGenerator { + + private String addonName; + private String dbUrl; + private String dbUser; + private String dbPassword; + private String dbTables; + private String optionsTables; + private String modelPackage; + private String servicePackage; + + private String basePath; + + private boolean genUI = false; + + + public AddonGenerator(String addonName, String dbUrl, String dbUser, String dbPassword, String dbTables, String modelPackage, String servicePackage) { + this.addonName = addonName; + this.dbUrl = dbUrl; + this.dbUser = dbUser; + this.dbPassword = dbPassword; + this.dbTables = dbTables; + this.modelPackage = modelPackage; + this.servicePackage = servicePackage; + this.basePath = PathKit.getWebRootPath() + "/../jpress-addon-" + addonName; + } + + + public AddonGenerator(String addonName, String dbUrl, String dbUser, String dbPassword, String dbTables, String optionsTables, String modelPackage, String servicePackage) { + this.addonName = addonName; + this.dbUrl = dbUrl; + this.dbUser = dbUser; + this.dbPassword = dbPassword; + this.dbTables = dbTables; + this.optionsTables = optionsTables; + this.modelPackage = modelPackage; + this.servicePackage = servicePackage; + this.basePath = PathKit.getWebRootPath() + "/../jpress-addon-" + addonName; + } + + + public boolean isGenUI() { + return genUI; + } + + public AddonGenerator setGenUI(boolean genUI) { + this.genUI = genUI; + return this; + } + + public void gen() { + + genCode(); + + } + + + private void genCode() { + + + JbootApplication.setBootArg("jboot.datasource.url", dbUrl); + JbootApplication.setBootArg("jboot.datasource.user", dbUser); + JbootApplication.setBootArg("jboot.datasource.password", dbPassword); + + String baseModelPackage = modelPackage + ".base"; + + String modelDir = basePath + "/src/main/java/" + modelPackage.replace(".", "/"); + String baseModelDir = basePath + "/src/main/java/" + baseModelPackage.replace(".", "/"); + + System.out.println("start generate... dir:" + modelDir); + + MetaBuilder metaBuilder = CodeGenHelpler.createMetaBuilder(); + metaBuilder.setGenerateRemarks(true); + List tableMetas = metaBuilder.build(); + + Set genTableNames = StrUtil.splitToSet(dbTables, ","); + tableMetas.removeIf(tableMeta -> genTableNames != null && !genTableNames.contains(tableMeta.name.toLowerCase())); + + + new BaseModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); + new ModelGenerator(modelPackage, baseModelPackage, modelDir).generate(tableMetas); + + String apiPath = basePath + "/src/main/java/" + servicePackage.replace(".", "/"); + String providerPath = basePath + "/src/main/java/" + servicePackage.replace(".", "/") + "/provider"; + + new ServiceApiGenerator(servicePackage, modelPackage, apiPath).generate(tableMetas); + new ServiceProviderGenerator(servicePackage, modelPackage, providerPath).generate(tableMetas); + + if (genUI) { + new AddonUIGenerator(basePath, addonName, modelPackage, tableMetas) + .genControllers() + .genEdit() + .genList(); + } + + Set optionsTableNames = StrUtil.splitToSet(optionsTables, ","); + if (optionsTableNames != null && optionsTableNames.size() > 0) { + tableMetas.removeIf(tableMeta -> !optionsTableNames.contains(tableMeta.name.toLowerCase())); + new BaseOptionsModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); + } + } +} diff --git a/codegen/src/main/java/io/jpress/codegen/ModuleGenerator.java b/codegen/src/main/java/io/jpress/codegen/ModuleGenerator.java index 83ce00a63f91893750b55c4a7ff30bb25590a654..4e97c620f9741012107d6e3739798a4c577f0951 100644 --- a/codegen/src/main/java/io/jpress/codegen/ModuleGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/ModuleGenerator.java @@ -1,220 +1,220 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen; - -import com.jfinal.kit.PathKit; -import com.jfinal.kit.StrKit; -import com.jfinal.plugin.activerecord.generator.MetaBuilder; -import com.jfinal.plugin.activerecord.generator.TableMeta; -import com.jfinal.template.Engine; -import io.jboot.app.JbootApplication; -import io.jboot.codegen.CodeGenHelpler; -import io.jboot.utils.StrUtil; -import io.jpress.codegen.generator.*; - -import java.io.File; -import java.util.*; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 根据数据库信息,生成 maven module - * @Package io.jpress.core.code - */ -public class ModuleGenerator { - - private String moduleName; - private String dbUrl; - private String dbUser; - private String dbPassword; - private String optionsTables; - private String dbTables; - private String modelPackage; - private String servicePackage; - - private String basePath; - - private boolean genUI = false; - - public ModuleGenerator(String moduleName, String dbUrl, String dbUser, String dbPassword, String dbTables, String modelPackage, String servicePackage) { - this.moduleName = moduleName; - this.dbUrl = dbUrl; - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.dbTables = dbTables; - this.modelPackage = modelPackage; - this.servicePackage = servicePackage; - this.basePath = PathKit.getWebRootPath() + "/../module-" + moduleName; - } - - public ModuleGenerator(String moduleName, String dbUrl, String dbUser, String dbPassword, String dbTables, String optionsTables, String modelPackage, String servicePackage) { - this.moduleName = moduleName; - this.dbUrl = dbUrl; - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.optionsTables = optionsTables; - this.dbTables = dbTables; - this.modelPackage = modelPackage; - this.servicePackage = servicePackage; - this.basePath = PathKit.getWebRootPath() + "/../module-" + moduleName; - } - - - public boolean isGenUI() { - return genUI; - } - - public ModuleGenerator setGenUI(boolean genUI) { - this.genUI = genUI; - return this; - } - - public void gen() { - - genModule(); - genPomXml(); - genCode(); - } - - private void genModule() { - String modelPath = basePath + "/module-" + moduleName + "-model"; - String webPath = basePath + "/module-" + moduleName + "-web"; - String serviceApiPath = basePath + "/module-" + moduleName + "-service-api"; - String serviceProviderPath = basePath + "/module-" + moduleName + "-service-provider"; - - File modelFile = new File(modelPath); - File webFile = new File(webPath); - File serviceApiFile = new File(serviceApiPath); - File serviceProviderFile = new File(serviceProviderPath); - - modelFile.mkdirs(); - webFile.mkdirs(); - serviceApiFile.mkdirs(); - serviceProviderFile.mkdirs(); - } - - private void genPomXml() { - - String modulePath = basePath; - String modelPath = basePath + "/module-" + moduleName + "-model"; - String webPath = basePath + "/module-" + moduleName + "-web"; - String serviceApiPath = basePath + "/module-" + moduleName + "-service-api"; - String serviceProviderPath = basePath + "/module-" + moduleName + "-service-provider"; - - - File modelFile = new File(modelPath); - File webFile = new File(webPath); - File serviceApiFile = new File(serviceApiPath); - File serviceProviderFile = new File(serviceProviderPath); - - makeSrcDirectory(modelFile); - makeSrcDirectory(webFile); - makeSrcDirectory(serviceApiFile); - makeSrcDirectory(serviceProviderFile); - - Map map = new HashMap(); - map.put("moduleName", moduleName); - Engine engine = new Engine(); - engine.setToClassPathSourceFactory(); // 从 class path 内读模板文件 - engine.addSharedMethod(new StrKit()); - - File modulePomXmlFile = new File(modulePath, "pom.xml"); - if (!modulePomXmlFile.exists()) { - engine.getTemplate("io/jpress/codegen/templates/pom_module_template.jf").render(map, modulePomXmlFile); - } - - File modelPomXmlFile = new File(modelFile, "pom.xml"); - if (!modelPomXmlFile.exists()) { - engine.getTemplate("io/jpress/codegen/templates/pom_model_template.jf").render(map, modelPomXmlFile); - } - - File webPomXmlFile = new File(webFile, "pom.xml"); - if (!webPomXmlFile.exists()) { - engine.getTemplate("io/jpress/codegen/templates/pom_web_template.jf").render(map, webPomXmlFile); - } - - File serviceApiPomXmlFile = new File(serviceApiFile, "pom.xml"); - if (!serviceApiPomXmlFile.exists()) { - engine.getTemplate("io/jpress/codegen/templates/pom_service_api_template.jf").render(map, serviceApiPomXmlFile); - } - - File serviceProviderPomXmlFile = new File(serviceProviderFile, "pom.xml"); - if (!serviceProviderPomXmlFile.exists()) { - engine.getTemplate("io/jpress/codegen/templates/pom_service_provider_template.jf").render(map, serviceProviderPomXmlFile); - } - - } - - private void makeSrcDirectory(File file) { - if (!file.isDirectory()) { - return; - } - - new File(file, "src/main/java").mkdirs(); - new File(file, "src/main/resources").mkdirs(); - new File(file, "src/test/java").mkdirs(); - new File(file, "src/test/resources").mkdirs(); - } - - - private void genCode() { - - String modelModuleName = "/module-" + moduleName + "-model"; - String serviceApiModuleName = "/module-" + moduleName + "-service-api"; - String serviceProviderModuleName = "/module-" + moduleName + "-service-provider"; - - JbootApplication.setBootArg("jboot.datasource.url", dbUrl); - JbootApplication.setBootArg("jboot.datasource.user", dbUser); - JbootApplication.setBootArg("jboot.datasource.password", dbPassword); - - String baseModelPackage = modelPackage + ".base"; - - String modelDir = basePath + modelModuleName + "/src/main/java/" + modelPackage.replace(".", "/"); - String baseModelDir = basePath + modelModuleName + "/src/main/java/" + baseModelPackage.replace(".", "/"); - - System.out.println("start generate... dir:" + modelDir); - - - Set genTableNames = StrUtil.splitToSet(dbTables, ","); - - MetaBuilder mb = CodeGenHelpler.createMetaBuilder(); - mb.setGenerateRemarks(true); - List tableMetas = mb.build(); - - tableMetas.removeIf(tableMeta -> genTableNames != null && !genTableNames.contains(tableMeta.name.toLowerCase())); - - - new BaseModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); - new ModelGenerator(modelPackage, baseModelPackage, modelDir).generate(tableMetas); - - String apiPath = basePath + serviceApiModuleName + "/src/main/java/" + servicePackage.replace(".", "/"); - String providerPath = basePath + serviceProviderModuleName + "/src/main/java/" + servicePackage.replace(".", "/") + "/provider"; - - new ServiceApiGenerator(servicePackage, modelPackage, apiPath).generate(tableMetas); - new ServiceProviderGenerator(servicePackage, modelPackage, providerPath).generate(tableMetas); - if (genUI) { - new ModuleUIGenerator(moduleName, modelPackage, tableMetas).genListener().genControllers().genEdit().genList(); - } - - Set optionsTableNames = StrUtil.splitToSet(optionsTables, ","); - if (optionsTableNames != null && optionsTableNames.size() > 0) { - tableMetas.removeIf(tableMeta -> !optionsTableNames.contains(tableMeta.name.toLowerCase())); - new BaseOptionsModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); - } - - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen; + +import com.jfinal.kit.PathKit; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.generator.MetaBuilder; +import com.jfinal.plugin.activerecord.generator.TableMeta; +import com.jfinal.template.Engine; +import io.jboot.app.JbootApplication; +import io.jboot.codegen.CodeGenHelpler; +import io.jboot.utils.StrUtil; +import io.jpress.codegen.generator.*; + +import java.io.File; +import java.util.*; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 根据数据库信息,生成 maven module + * @Package io.jpress.core.code + */ +public class ModuleGenerator { + + private String moduleName; + private String dbUrl; + private String dbUser; + private String dbPassword; + private String optionsTables; + private String dbTables; + private String modelPackage; + private String servicePackage; + + private String basePath; + + private boolean genUI = false; + + public ModuleGenerator(String moduleName, String dbUrl, String dbUser, String dbPassword, String dbTables, String modelPackage, String servicePackage) { + this.moduleName = moduleName; + this.dbUrl = dbUrl; + this.dbUser = dbUser; + this.dbPassword = dbPassword; + this.dbTables = dbTables; + this.modelPackage = modelPackage; + this.servicePackage = servicePackage; + this.basePath = PathKit.getWebRootPath() + "/../module-" + moduleName; + } + + public ModuleGenerator(String moduleName, String dbUrl, String dbUser, String dbPassword, String dbTables, String optionsTables, String modelPackage, String servicePackage) { + this.moduleName = moduleName; + this.dbUrl = dbUrl; + this.dbUser = dbUser; + this.dbPassword = dbPassword; + this.optionsTables = optionsTables; + this.dbTables = dbTables; + this.modelPackage = modelPackage; + this.servicePackage = servicePackage; + this.basePath = PathKit.getWebRootPath() + "/../module-" + moduleName; + } + + + public boolean isGenUI() { + return genUI; + } + + public ModuleGenerator setGenUI(boolean genUI) { + this.genUI = genUI; + return this; + } + + public void gen() { + + genModule(); + genPomXml(); + genCode(); + } + + private void genModule() { + String modelPath = basePath + "/module-" + moduleName + "-model"; + String webPath = basePath + "/module-" + moduleName + "-web"; + String serviceApiPath = basePath + "/module-" + moduleName + "-service-api"; + String serviceProviderPath = basePath + "/module-" + moduleName + "-service-provider"; + + File modelFile = new File(modelPath); + File webFile = new File(webPath); + File serviceApiFile = new File(serviceApiPath); + File serviceProviderFile = new File(serviceProviderPath); + + modelFile.mkdirs(); + webFile.mkdirs(); + serviceApiFile.mkdirs(); + serviceProviderFile.mkdirs(); + } + + private void genPomXml() { + + String modulePath = basePath; + String modelPath = basePath + "/module-" + moduleName + "-model"; + String webPath = basePath + "/module-" + moduleName + "-web"; + String serviceApiPath = basePath + "/module-" + moduleName + "-service-api"; + String serviceProviderPath = basePath + "/module-" + moduleName + "-service-provider"; + + + File modelFile = new File(modelPath); + File webFile = new File(webPath); + File serviceApiFile = new File(serviceApiPath); + File serviceProviderFile = new File(serviceProviderPath); + + makeSrcDirectory(modelFile); + makeSrcDirectory(webFile); + makeSrcDirectory(serviceApiFile); + makeSrcDirectory(serviceProviderFile); + + Map map = new HashMap(); + map.put("moduleName", moduleName); + Engine engine = new Engine(); + engine.setToClassPathSourceFactory(); // 从 class path 内读模板文件 + engine.addSharedMethod(new StrKit()); + + File modulePomXmlFile = new File(modulePath, "pom.xml"); + if (!modulePomXmlFile.exists()) { + engine.getTemplate("io/jpress/codegen/templates/pom_module_template.jf").render(map, modulePomXmlFile); + } + + File modelPomXmlFile = new File(modelFile, "pom.xml"); + if (!modelPomXmlFile.exists()) { + engine.getTemplate("io/jpress/codegen/templates/pom_model_template.jf").render(map, modelPomXmlFile); + } + + File webPomXmlFile = new File(webFile, "pom.xml"); + if (!webPomXmlFile.exists()) { + engine.getTemplate("io/jpress/codegen/templates/pom_web_template.jf").render(map, webPomXmlFile); + } + + File serviceApiPomXmlFile = new File(serviceApiFile, "pom.xml"); + if (!serviceApiPomXmlFile.exists()) { + engine.getTemplate("io/jpress/codegen/templates/pom_service_api_template.jf").render(map, serviceApiPomXmlFile); + } + + File serviceProviderPomXmlFile = new File(serviceProviderFile, "pom.xml"); + if (!serviceProviderPomXmlFile.exists()) { + engine.getTemplate("io/jpress/codegen/templates/pom_service_provider_template.jf").render(map, serviceProviderPomXmlFile); + } + + } + + private void makeSrcDirectory(File file) { + if (!file.isDirectory()) { + return; + } + + new File(file, "src/main/java").mkdirs(); + new File(file, "src/main/resources").mkdirs(); + new File(file, "src/test/java").mkdirs(); + new File(file, "src/test/resources").mkdirs(); + } + + + private void genCode() { + + String modelModuleName = "/module-" + moduleName + "-model"; + String serviceApiModuleName = "/module-" + moduleName + "-service-api"; + String serviceProviderModuleName = "/module-" + moduleName + "-service-provider"; + + JbootApplication.setBootArg("jboot.datasource.url", dbUrl); + JbootApplication.setBootArg("jboot.datasource.user", dbUser); + JbootApplication.setBootArg("jboot.datasource.password", dbPassword); + + String baseModelPackage = modelPackage + ".base"; + + String modelDir = basePath + modelModuleName + "/src/main/java/" + modelPackage.replace(".", "/"); + String baseModelDir = basePath + modelModuleName + "/src/main/java/" + baseModelPackage.replace(".", "/"); + + System.out.println("start generate... dir:" + modelDir); + + + Set genTableNames = StrUtil.splitToSet(dbTables, ","); + + MetaBuilder mb = CodeGenHelpler.createMetaBuilder(); + mb.setGenerateRemarks(true); + List tableMetas = mb.build(); + + tableMetas.removeIf(tableMeta -> genTableNames != null && !genTableNames.contains(tableMeta.name.toLowerCase())); + + + new BaseModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); + new ModelGenerator(modelPackage, baseModelPackage, modelDir).generate(tableMetas); + + String apiPath = basePath + serviceApiModuleName + "/src/main/java/" + servicePackage.replace(".", "/"); + String providerPath = basePath + serviceProviderModuleName + "/src/main/java/" + servicePackage.replace(".", "/") + "/provider"; + + new ServiceApiGenerator(servicePackage, modelPackage, apiPath).generate(tableMetas); + new ServiceProviderGenerator(servicePackage, modelPackage, providerPath).generate(tableMetas); + if (genUI) { + new ModuleUIGenerator(moduleName, modelPackage, tableMetas).genListener().genControllers().genEdit().genList(); + } + + Set optionsTableNames = StrUtil.splitToSet(optionsTables, ","); + if (optionsTableNames != null && optionsTableNames.size() > 0) { + tableMetas.removeIf(tableMeta -> !optionsTableNames.contains(tableMeta.name.toLowerCase())); + new BaseOptionsModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); + } + + } + +} diff --git a/codegen/src/main/java/io/jpress/codegen/SystemGenerator.java b/codegen/src/main/java/io/jpress/codegen/SystemGenerator.java index 4414c74ca8e0afa42840f736ce37d11b4c738629..6bc5b6b4c7ae84e0dc8fe9dbd936244b99314690 100644 --- a/codegen/src/main/java/io/jpress/codegen/SystemGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/SystemGenerator.java @@ -1,90 +1,90 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen; - -import com.jfinal.kit.PathKit; -import com.jfinal.plugin.activerecord.generator.MetaBuilder; -import com.jfinal.plugin.activerecord.generator.TableMeta; -import io.jboot.app.JbootApplication; -import io.jboot.codegen.CodeGenHelpler; -import io.jboot.utils.StrUtil; -import io.jpress.codegen.generator.*; - -import java.util.List; -import java.util.Set; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 根据数据库信息,生成 JPress 系统代码 - * @Package io.jpress.core.code - */ -public class SystemGenerator { - - public static void main(String[] args) { - - String dbTables = "user,attachment,menu,option,payment_record,permission,role,utm," + - "wechat_menu,wechat_reply," + - "member,member_group,member_dist_amount,member_joined_record,member_price," + - "user_address,user_amount,user_amount_statement,user_amount_payout," + - "coupon,coupon_code,coupon_used_record," + - "user_cart,user_order,user_order_item,user_order_delivery,user_order_invoice," + - "user_openid,user_favorite,user_tag," + - "payment_record"; - - String optionsTables = "coupon,member,member_group,product,product_category,user_address," + - "user_amount_statement,user_amount_payout,user_cart,user_order,user_order_item,user_order_delivery,user_order_invoice," + - "payment_record,user_openid,member_joined_record,user_favorite,user_tag"; - - JbootApplication.setBootArg("jboot.datasource.url", "jdbc:mysql://127.0.0.1:3306/jpress3"); - JbootApplication.setBootArg("jboot.datasource.user", "root"); - JbootApplication.setBootArg("jboot.datasource.password", "123456"); - - String modelPackage = "io.jpress.model"; - - String baseModelPackage = modelPackage + ".base"; - - String modelDir = PathKit.getWebRootPath() + "/../jpress-model/src/main/java/" + modelPackage.replace(".", "/"); - String baseModelDir = PathKit.getWebRootPath() + "/../jpress-model/src/main/java/" + baseModelPackage.replace(".", "/"); - - System.out.println("start generate...dir:" + modelDir); - - Set genTableNames = StrUtil.splitToSet(dbTables, ","); - MetaBuilder metaBuilder = CodeGenHelpler.createMetaBuilder(); - metaBuilder.setGenerateRemarks(true); - List tableMetas = metaBuilder.build(); - tableMetas.removeIf(tableMeta -> genTableNames != null && !genTableNames.contains(tableMeta.name.toLowerCase())); - - - new BaseModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); - new ModelGenerator(modelPackage, baseModelPackage, modelDir).generate(tableMetas); - - String servicePackage = "io.jpress.service"; - String apiPath = PathKit.getWebRootPath() + "/../jpress-service-api/src/main/java/" + servicePackage.replace(".", "/"); - String providerPath = PathKit.getWebRootPath() + "/../jpress-service-provider/src/main/java/" + servicePackage.replace(".", "/") + "/provider"; - - - new ServiceApiGenerator(servicePackage, modelPackage, apiPath).generate(tableMetas); - new ServiceProviderGenerator(servicePackage, modelPackage, providerPath).generate(tableMetas); - - Set optionsTableNames = StrUtil.splitToSet(optionsTables, ","); - if (optionsTableNames != null && optionsTableNames.size() > 0) { - tableMetas.removeIf(tableMeta -> !optionsTableNames.contains(tableMeta.name.toLowerCase())); - new BaseOptionsModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); - } - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen; + +import com.jfinal.kit.PathKit; +import com.jfinal.plugin.activerecord.generator.MetaBuilder; +import com.jfinal.plugin.activerecord.generator.TableMeta; +import io.jboot.app.JbootApplication; +import io.jboot.codegen.CodeGenHelpler; +import io.jboot.utils.StrUtil; +import io.jpress.codegen.generator.*; + +import java.util.List; +import java.util.Set; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 根据数据库信息,生成 JPress 系统代码 + * @Package io.jpress.core.code + */ +public class SystemGenerator { + + public static void main(String[] args) { + + String dbTables = "user,attachment,menu,option,payment_record,permission,role,utm," + + "wechat_menu,wechat_reply," + + "member,member_group,member_dist_amount,member_joined_record,member_price," + + "user_address,user_amount,user_amount_statement,user_amount_payout," + + "coupon,coupon_code,coupon_used_record," + + "user_cart,user_order,user_order_item,user_order_delivery,user_order_invoice," + + "user_openid,user_favorite,user_tag," + + "payment_record"; + + String optionsTables = "coupon,member,member_group,product,product_category,user_address," + + "user_amount_statement,user_amount_payout,user_cart,user_order,user_order_item,user_order_delivery,user_order_invoice," + + "payment_record,user_openid,member_joined_record,user_favorite,user_tag"; + + JbootApplication.setBootArg("jboot.datasource.url", "jdbc:mysql://127.0.0.1:3306/jpress3"); + JbootApplication.setBootArg("jboot.datasource.user", "root"); + JbootApplication.setBootArg("jboot.datasource.password", "123456"); + + String modelPackage = "io.jpress.model"; + + String baseModelPackage = modelPackage + ".base"; + + String modelDir = PathKit.getWebRootPath() + "/../jpress-model/src/main/java/" + modelPackage.replace(".", "/"); + String baseModelDir = PathKit.getWebRootPath() + "/../jpress-model/src/main/java/" + baseModelPackage.replace(".", "/"); + + System.out.println("start generate...dir:" + modelDir); + + Set genTableNames = StrUtil.splitToSet(dbTables, ","); + MetaBuilder metaBuilder = CodeGenHelpler.createMetaBuilder(); + metaBuilder.setGenerateRemarks(true); + List tableMetas = metaBuilder.build(); + tableMetas.removeIf(tableMeta -> genTableNames != null && !genTableNames.contains(tableMeta.name.toLowerCase())); + + + new BaseModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); + new ModelGenerator(modelPackage, baseModelPackage, modelDir).generate(tableMetas); + + String servicePackage = "io.jpress.service"; + String apiPath = PathKit.getWebRootPath() + "/../jpress-service-api/src/main/java/" + servicePackage.replace(".", "/"); + String providerPath = PathKit.getWebRootPath() + "/../jpress-service-provider/src/main/java/" + servicePackage.replace(".", "/") + "/provider"; + + + new ServiceApiGenerator(servicePackage, modelPackage, apiPath).generate(tableMetas); + new ServiceProviderGenerator(servicePackage, modelPackage, providerPath).generate(tableMetas); + + Set optionsTableNames = StrUtil.splitToSet(optionsTables, ","); + if (optionsTableNames != null && optionsTableNames.size() > 0) { + tableMetas.removeIf(tableMeta -> !optionsTableNames.contains(tableMeta.name.toLowerCase())); + new BaseOptionsModelGenerator(baseModelPackage, baseModelDir).generate(tableMetas); + } + } + +} diff --git a/codegen/src/main/java/io/jpress/codegen/Tester.java b/codegen/src/main/java/io/jpress/codegen/Tester.java index 61aa91274756c8e6ddf01732d30e9dc148149872..94ce9daedec66055c6152acd5764dee8eac05fc8 100644 --- a/codegen/src/main/java/io/jpress/codegen/Tester.java +++ b/codegen/src/main/java/io/jpress/codegen/Tester.java @@ -1,42 +1,42 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Package io.jboot.codegen - */ -public class Tester { - - - private static String dbUrl = "jdbc:mysql://127.0.0.1:3306/jpress3"; - private static String dbUser = "root"; - private static String dbPassword = ""; - - - private static String moduleName = "page"; - private static String dbTables = "single_page"; - private static String modelPackage = "io.jpress.module.page.model"; - private static String servicePackage = "io.jpress.module.page.service"; - - public static void main(String[] args) { - - ModuleGenerator moduleGenerator = new ModuleGenerator(moduleName, dbUrl, dbUser, dbPassword, dbTables, modelPackage, servicePackage); - moduleGenerator.gen(); - - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Package io.jboot.codegen + */ +public class Tester { + + + private static String dbUrl = "jdbc:mysql://127.0.0.1:3306/jpress3"; + private static String dbUser = "root"; + private static String dbPassword = ""; + + + private static String moduleName = "page"; + private static String dbTables = "single_page"; + private static String modelPackage = "io.jpress.module.page.model"; + private static String servicePackage = "io.jpress.module.page.service"; + + public static void main(String[] args) { + + ModuleGenerator moduleGenerator = new ModuleGenerator(moduleName, dbUrl, dbUser, dbPassword, dbTables, modelPackage, servicePackage); + moduleGenerator.gen(); + + } +} diff --git a/codegen/src/main/java/io/jpress/codegen/generator/AddonUIGenerator.java b/codegen/src/main/java/io/jpress/codegen/generator/AddonUIGenerator.java index 8ec1ff5dff515b8bfeee78ed71991c5c82eafc6f..eba3486a2fd6881434682784322c3c294b0002c1 100644 --- a/codegen/src/main/java/io/jpress/codegen/generator/AddonUIGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/generator/AddonUIGenerator.java @@ -1,159 +1,159 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen.generator; - -import com.jfinal.kit.Kv; -import com.jfinal.kit.StrKit; -import com.jfinal.plugin.activerecord.generator.TableMeta; -import com.jfinal.template.Engine; -import com.jfinal.template.source.ClassPathSourceFactory; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.List; - -public class AddonUIGenerator { - - private String moduleName;//product - private String modulePackage;//io.jpress.module.product - - private String modelPackage;//io.jpress.module.product.model - - - private String templatesDir = "io/jpress/codegen/templates/"; - - private Kv data; - private String[] templates = { "ui_controller_template_for_addon.jf", "ui_edit_template.jf", "ui_list_template.jf"}; - public static final int UI_CONTROLLER = 1; - public static final int UI_EDIT = 2; - public static final int UI_LIST = 3; - - - private String controllerOutputDir; - private String htmlOutputDir; - - private String targetTemplate; - private String targetOutputDirFile; - - private List tableMetaList; - - private String basePath; - - private Engine engine = Engine.create("forUI"); - - public static void main(String[] args) { - - } - - public AddonUIGenerator(String basePath, String moduleName, String modelPackage, List tableMetaList) { - - this.basePath = basePath; - - this.tableMetaList = tableMetaList; - this.moduleName = moduleName; - this.modelPackage = modelPackage; - this.modulePackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); - - modulePackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); - - String moduleListenerPakcage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); - String controllerPackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")) + ".controller"; - - - controllerOutputDir = basePath + "/src/main/java/" + controllerPackage.replace(".", "/"); - htmlOutputDir = basePath + "/src/main/webapp/views/"; - - data = Kv.by("moduleName", moduleName);//product - data.set("upcasedModuleName", StrKit.firstCharToUpperCase(moduleName));//Product - data.set("modulePackage", modulePackage);//io.jpress.module.product - data.set("modelPackage", modelPackage);//io.jpress.module.product.model - data.set("moduleListenerPakcage", moduleListenerPakcage);//io.jpress.module.product - data.set("controllerPackage", controllerPackage);//io.jpress.module.product.controller - - engine.setSourceFactory(new ClassPathSourceFactory()); - engine.addSharedMethod(new StrKit()); - - } - - - public AddonUIGenerator genControllers() { - generate(AddonUIGenerator.UI_CONTROLLER); - return this; - } - - public AddonUIGenerator genEdit() { - generate(AddonUIGenerator.UI_EDIT); - return this; - } - - public AddonUIGenerator genList() { - generate(AddonUIGenerator.UI_LIST); - return this; - } - - public void generate(int genType) { - - String targetOutputDir = ""; - - for (TableMeta tableMeta : tableMetaList) { - data.set("tableMeta", tableMeta); - String lowerCaseModelName = StrKit.firstCharToLowerCase(tableMeta.modelName); - data.set("lowerCaseModelName", lowerCaseModelName); - - if (AddonUIGenerator.UI_CONTROLLER == genType) { - targetTemplate = templatesDir + templates[0]; - targetOutputDir = controllerOutputDir; - targetOutputDirFile = targetOutputDir + File.separator + "_" + tableMeta.modelName + "Controller" + ".java"; - } - - if (AddonUIGenerator.UI_EDIT == genType) { - targetTemplate = templatesDir + templates[1]; - targetOutputDir = htmlOutputDir; - targetOutputDirFile = targetOutputDir + File.separator + tableMeta.name + "_edit.html"; - } - if (AddonUIGenerator.UI_LIST == genType) { - targetTemplate = templatesDir + templates[2]; - targetOutputDir = htmlOutputDir; - targetOutputDirFile = targetOutputDir + File.separator + tableMeta.name + "_list.html"; - } - // tableMeta.columnMetas.get(0).remarks - String content = engine.getTemplate(targetTemplate).renderToString(data); - - // - File dir = new File(targetOutputDir); - if (!dir.exists()) { - dir.mkdirs(); - } - File targetFile = new File(targetOutputDirFile); - if (targetFile.exists()) { - return; - } - try { - FileWriter fw = new FileWriter(targetOutputDirFile); - try { - fw.write(content); - } finally { - fw.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen.generator; + +import com.jfinal.kit.Kv; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.generator.TableMeta; +import com.jfinal.template.Engine; +import com.jfinal.template.source.ClassPathSourceFactory; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +public class AddonUIGenerator { + + private String moduleName;//product + private String modulePackage;//io.jpress.module.product + + private String modelPackage;//io.jpress.module.product.model + + + private String templatesDir = "io/jpress/codegen/templates/"; + + private Kv data; + private String[] templates = { "ui_controller_template_for_addon.jf", "ui_edit_template.jf", "ui_list_template.jf"}; + public static final int UI_CONTROLLER = 1; + public static final int UI_EDIT = 2; + public static final int UI_LIST = 3; + + + private String controllerOutputDir; + private String htmlOutputDir; + + private String targetTemplate; + private String targetOutputDirFile; + + private List tableMetaList; + + private String basePath; + + private Engine engine = Engine.create("forUI"); + + public static void main(String[] args) { + + } + + public AddonUIGenerator(String basePath, String moduleName, String modelPackage, List tableMetaList) { + + this.basePath = basePath; + + this.tableMetaList = tableMetaList; + this.moduleName = moduleName; + this.modelPackage = modelPackage; + this.modulePackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); + + modulePackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); + + String moduleListenerPakcage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); + String controllerPackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")) + ".controller"; + + + controllerOutputDir = basePath + "/src/main/java/" + controllerPackage.replace(".", "/"); + htmlOutputDir = basePath + "/src/main/webapp/views/"; + + data = Kv.by("moduleName", moduleName);//product + data.set("upcasedModuleName", StrKit.firstCharToUpperCase(moduleName));//Product + data.set("modulePackage", modulePackage);//io.jpress.module.product + data.set("modelPackage", modelPackage);//io.jpress.module.product.model + data.set("moduleListenerPakcage", moduleListenerPakcage);//io.jpress.module.product + data.set("controllerPackage", controllerPackage);//io.jpress.module.product.controller + + engine.setSourceFactory(new ClassPathSourceFactory()); + engine.addSharedMethod(new StrKit()); + + } + + + public AddonUIGenerator genControllers() { + generate(AddonUIGenerator.UI_CONTROLLER); + return this; + } + + public AddonUIGenerator genEdit() { + generate(AddonUIGenerator.UI_EDIT); + return this; + } + + public AddonUIGenerator genList() { + generate(AddonUIGenerator.UI_LIST); + return this; + } + + public void generate(int genType) { + + String targetOutputDir = ""; + + for (TableMeta tableMeta : tableMetaList) { + data.set("tableMeta", tableMeta); + String lowerCaseModelName = StrKit.firstCharToLowerCase(tableMeta.modelName); + data.set("lowerCaseModelName", lowerCaseModelName); + + if (AddonUIGenerator.UI_CONTROLLER == genType) { + targetTemplate = templatesDir + templates[0]; + targetOutputDir = controllerOutputDir; + targetOutputDirFile = targetOutputDir + File.separator + "_" + tableMeta.modelName + "Controller" + ".java"; + } + + if (AddonUIGenerator.UI_EDIT == genType) { + targetTemplate = templatesDir + templates[1]; + targetOutputDir = htmlOutputDir; + targetOutputDirFile = targetOutputDir + File.separator + tableMeta.name + "_edit.html"; + } + if (AddonUIGenerator.UI_LIST == genType) { + targetTemplate = templatesDir + templates[2]; + targetOutputDir = htmlOutputDir; + targetOutputDirFile = targetOutputDir + File.separator + tableMeta.name + "_list.html"; + } + // tableMeta.columnMetas.get(0).remarks + String content = engine.getTemplate(targetTemplate).renderToString(data); + + // + File dir = new File(targetOutputDir); + if (!dir.exists()) { + dir.mkdirs(); + } + File targetFile = new File(targetOutputDirFile); + if (targetFile.exists()) { + return; + } + try { + FileWriter fw = new FileWriter(targetOutputDirFile); + try { + fw.write(content); + } finally { + fw.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + +} diff --git a/codegen/src/main/java/io/jpress/codegen/generator/BaseModelGenerator.java b/codegen/src/main/java/io/jpress/codegen/generator/BaseModelGenerator.java index 12e5066e14329de590b23f73eae8adb8866b8663..52212298594a38e066fe3b67e77b288553e425a7 100644 --- a/codegen/src/main/java/io/jpress/codegen/generator/BaseModelGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/generator/BaseModelGenerator.java @@ -1,30 +1,30 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen.generator; - - -public class BaseModelGenerator extends com.jfinal.plugin.activerecord.generator.BaseModelGenerator { - - public BaseModelGenerator(String baseModelPackageName, - String baseModelOutputDir) { - super(baseModelPackageName, baseModelOutputDir); - - this.template = "/io/jpress/codegen/templates/base_model_template.jf"; - - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen.generator; + + +public class BaseModelGenerator extends com.jfinal.plugin.activerecord.generator.BaseModelGenerator { + + public BaseModelGenerator(String baseModelPackageName, + String baseModelOutputDir) { + super(baseModelPackageName, baseModelOutputDir); + + this.template = "/io/jpress/codegen/templates/base_model_template.jf"; + + } + + +} diff --git a/codegen/src/main/java/io/jpress/codegen/generator/BaseOptionsModelGenerator.java b/codegen/src/main/java/io/jpress/codegen/generator/BaseOptionsModelGenerator.java index 4e153b064d60dd4c0eb8a37e97d96c75e732dac0..5c62c9b3ec5f40a424a3c43a4805b901a583748d 100644 --- a/codegen/src/main/java/io/jpress/codegen/generator/BaseOptionsModelGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/generator/BaseOptionsModelGenerator.java @@ -1,31 +1,31 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen.generator; - - -public class BaseOptionsModelGenerator extends com.jfinal.plugin.activerecord.generator.BaseModelGenerator { - - public BaseOptionsModelGenerator(String baseModelPackageName, - String baseModelOutputDir) { - super(baseModelPackageName, baseModelOutputDir); - - this.template = "/io/jpress/codegen/templates/base_options_model_template.jf"; - - - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen.generator; + + +public class BaseOptionsModelGenerator extends com.jfinal.plugin.activerecord.generator.BaseModelGenerator { + + public BaseOptionsModelGenerator(String baseModelPackageName, + String baseModelOutputDir) { + super(baseModelPackageName, baseModelOutputDir); + + this.template = "/io/jpress/codegen/templates/base_options_model_template.jf"; + + + } + + +} diff --git a/codegen/src/main/java/io/jpress/codegen/generator/ModelGenerator.java b/codegen/src/main/java/io/jpress/codegen/generator/ModelGenerator.java index 77e8b48d8b0c58352a2ea13380ce36e0c34140cd..dada4d160676528df55d244c0c54c4b5ff147650 100644 --- a/codegen/src/main/java/io/jpress/codegen/generator/ModelGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/generator/ModelGenerator.java @@ -1,31 +1,31 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen.generator; - - - -public class ModelGenerator extends com.jfinal.plugin.activerecord.generator.ModelGenerator { - - public ModelGenerator(String modelPackageName, - String baseModelPackageName, String modelOutputDir) { - super(modelPackageName, baseModelPackageName, modelOutputDir); - - this.template = "/io/jpress/codegen/templates/model_template.jf"; - - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen.generator; + + + +public class ModelGenerator extends com.jfinal.plugin.activerecord.generator.ModelGenerator { + + public ModelGenerator(String modelPackageName, + String baseModelPackageName, String modelOutputDir) { + super(modelPackageName, baseModelPackageName, modelOutputDir); + + this.template = "/io/jpress/codegen/templates/model_template.jf"; + + } + + +} diff --git a/codegen/src/main/java/io/jpress/codegen/generator/ModuleUIGenerator.java b/codegen/src/main/java/io/jpress/codegen/generator/ModuleUIGenerator.java index 750f6b6f198e0bf2584090b275538e46953498f1..48e18099fdd1d50971566210cee6904ad1d68831 100644 --- a/codegen/src/main/java/io/jpress/codegen/generator/ModuleUIGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/generator/ModuleUIGenerator.java @@ -1,173 +1,173 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen.generator; - -import com.jfinal.kit.Kv; -import com.jfinal.kit.PathKit; -import com.jfinal.kit.StrKit; -import com.jfinal.plugin.activerecord.generator.TableMeta; -import com.jfinal.template.Engine; -import com.jfinal.template.source.ClassPathSourceFactory; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.List; - -public class ModuleUIGenerator { - - private String moduleName;//product - private String modulePackage;//io.jpress.module.product - - private String modelPackage;//io.jpress.module.product.model - - - private String basePath; - private String webPath; - private String templatesDir = "io/jpress/codegen/templates/"; - - private Kv data; - private String[] templates = {"ui_listener_template.jf", "ui_controller_template.jf", "ui_edit_template.jf", "ui_list_template.jf"}; - public static final int UI_MODULELISTENER = 0; - public static final int UI_CONTROLLER = 1; - public static final int UI_EDIT = 2; - public static final int UI_LIST = 3; - - - private String moduleListenerOutputDir; - private String controllerOutputDir; - private String htmlOutputDir; - - private String targetTemplate; - private String targetOutputDirFile; - - List tableMetaList; - - private Engine engine = Engine.create("forUI"); - - public static void main(String[] args) { - - } - - public ModuleUIGenerator(String moduleName, String modelPackage, List tableMetaList) { - - this.tableMetaList = tableMetaList; - this.moduleName = moduleName; - this.modelPackage = modelPackage; - modulePackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); - - basePath = PathKit.getWebRootPath() + "/../module-" + moduleName; - webPath = basePath + "/module-" + moduleName + "-web"; - - String upcasedModuleName = StrKit.firstCharToUpperCase(moduleName); - - String moduleListenerPakcage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); - String controllerPackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")) + ".controller"; - - - moduleListenerOutputDir = webPath + "/src/main/java/" + moduleListenerPakcage.replace(".", "/"); - controllerOutputDir = webPath + "/src/main/java/" + controllerPackage.replace(".", "/"); - htmlOutputDir = webPath + "/src/main/webapp/WEB-INF/views/admin/" + moduleName; - - data = Kv.by("moduleName", moduleName);//product - data.set("upcasedModuleName", upcasedModuleName);//Product - data.set("modulePackage", modulePackage);//io.jpress.module.product - data.set("modelPackage", modelPackage);//io.jpress.module.product.model - data.set("moduleListenerPakcage", moduleListenerPakcage);//io.jpress.module.product - data.set("controllerPackage", controllerPackage);//io.jpress.module.product.controller - - engine.setSourceFactory(new ClassPathSourceFactory()); - engine.addSharedMethod(new StrKit()); - - } - - public ModuleUIGenerator genListener() { - generate(ModuleUIGenerator.UI_MODULELISTENER); - return this; - } - - public ModuleUIGenerator genControllers() { - generate(ModuleUIGenerator.UI_CONTROLLER); - return this; - } - - public ModuleUIGenerator genEdit() { - generate(ModuleUIGenerator.UI_EDIT); - return this; - } - - public ModuleUIGenerator genList() { - generate(ModuleUIGenerator.UI_LIST); - return this; - } - - public void generate(int genType) { - - String targetOutputDir = ""; - if (ModuleUIGenerator.UI_MODULELISTENER == genType) { - targetTemplate = templatesDir + templates[0]; - targetOutputDir = moduleListenerOutputDir; - targetOutputDirFile = targetOutputDir + File.separator + StrKit.firstCharToUpperCase(moduleName) + "ModuleInitializer" + ".java"; - } - - for (TableMeta tableMeta : tableMetaList) { - data.set("tableMeta", tableMeta); - String lowerCaseModelName = StrKit.firstCharToLowerCase(tableMeta.modelName); - data.set("lowerCaseModelName", lowerCaseModelName); - - if (ModuleUIGenerator.UI_CONTROLLER == genType) { - targetTemplate = templatesDir + templates[1]; - targetOutputDir = controllerOutputDir; - targetOutputDirFile = targetOutputDir + File.separator + "_" + tableMeta.modelName + "Controller" + ".java"; - } - - if (ModuleUIGenerator.UI_EDIT == genType) { - targetTemplate = templatesDir + templates[2]; - targetOutputDir = htmlOutputDir; - targetOutputDirFile = targetOutputDir + File.separator + tableMeta.name + "_edit.html"; - } - if (ModuleUIGenerator.UI_LIST == genType) { - targetTemplate = templatesDir + templates[3]; - targetOutputDir = htmlOutputDir; - targetOutputDirFile = targetOutputDir + File.separator + tableMeta.name + "_list.html"; - } - // tableMeta.columnMetas.get(0).remarks - String content = engine.getTemplate(targetTemplate).renderToString(data); - - // - File dir = new File(targetOutputDir); - if (!dir.exists()) { - dir.mkdirs(); - } - File targetFile = new File(targetOutputDirFile); - if (targetFile.exists()) { - return; - } - try { - FileWriter fw = new FileWriter(targetOutputDirFile); - try { - fw.write(content); - } finally { - fw.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen.generator; + +import com.jfinal.kit.Kv; +import com.jfinal.kit.PathKit; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.generator.TableMeta; +import com.jfinal.template.Engine; +import com.jfinal.template.source.ClassPathSourceFactory; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +public class ModuleUIGenerator { + + private String moduleName;//product + private String modulePackage;//io.jpress.module.product + + private String modelPackage;//io.jpress.module.product.model + + + private String basePath; + private String webPath; + private String templatesDir = "io/jpress/codegen/templates/"; + + private Kv data; + private String[] templates = {"ui_listener_template.jf", "ui_controller_template.jf", "ui_edit_template.jf", "ui_list_template.jf"}; + public static final int UI_MODULELISTENER = 0; + public static final int UI_CONTROLLER = 1; + public static final int UI_EDIT = 2; + public static final int UI_LIST = 3; + + + private String moduleListenerOutputDir; + private String controllerOutputDir; + private String htmlOutputDir; + + private String targetTemplate; + private String targetOutputDirFile; + + List tableMetaList; + + private Engine engine = Engine.create("forUI"); + + public static void main(String[] args) { + + } + + public ModuleUIGenerator(String moduleName, String modelPackage, List tableMetaList) { + + this.tableMetaList = tableMetaList; + this.moduleName = moduleName; + this.modelPackage = modelPackage; + modulePackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); + + basePath = PathKit.getWebRootPath() + "/../module-" + moduleName; + webPath = basePath + "/module-" + moduleName + "-web"; + + String upcasedModuleName = StrKit.firstCharToUpperCase(moduleName); + + String moduleListenerPakcage = modelPackage.substring(0, modelPackage.lastIndexOf(".")); + String controllerPackage = modelPackage.substring(0, modelPackage.lastIndexOf(".")) + ".controller"; + + + moduleListenerOutputDir = webPath + "/src/main/java/" + moduleListenerPakcage.replace(".", "/"); + controllerOutputDir = webPath + "/src/main/java/" + controllerPackage.replace(".", "/"); + htmlOutputDir = webPath + "/src/main/webapp/WEB-INF/views/admin/" + moduleName; + + data = Kv.by("moduleName", moduleName);//product + data.set("upcasedModuleName", upcasedModuleName);//Product + data.set("modulePackage", modulePackage);//io.jpress.module.product + data.set("modelPackage", modelPackage);//io.jpress.module.product.model + data.set("moduleListenerPakcage", moduleListenerPakcage);//io.jpress.module.product + data.set("controllerPackage", controllerPackage);//io.jpress.module.product.controller + + engine.setSourceFactory(new ClassPathSourceFactory()); + engine.addSharedMethod(new StrKit()); + + } + + public ModuleUIGenerator genListener() { + generate(ModuleUIGenerator.UI_MODULELISTENER); + return this; + } + + public ModuleUIGenerator genControllers() { + generate(ModuleUIGenerator.UI_CONTROLLER); + return this; + } + + public ModuleUIGenerator genEdit() { + generate(ModuleUIGenerator.UI_EDIT); + return this; + } + + public ModuleUIGenerator genList() { + generate(ModuleUIGenerator.UI_LIST); + return this; + } + + public void generate(int genType) { + + String targetOutputDir = ""; + if (ModuleUIGenerator.UI_MODULELISTENER == genType) { + targetTemplate = templatesDir + templates[0]; + targetOutputDir = moduleListenerOutputDir; + targetOutputDirFile = targetOutputDir + File.separator + StrKit.firstCharToUpperCase(moduleName) + "ModuleInitializer" + ".java"; + } + + for (TableMeta tableMeta : tableMetaList) { + data.set("tableMeta", tableMeta); + String lowerCaseModelName = StrKit.firstCharToLowerCase(tableMeta.modelName); + data.set("lowerCaseModelName", lowerCaseModelName); + + if (ModuleUIGenerator.UI_CONTROLLER == genType) { + targetTemplate = templatesDir + templates[1]; + targetOutputDir = controllerOutputDir; + targetOutputDirFile = targetOutputDir + File.separator + "_" + tableMeta.modelName + "Controller" + ".java"; + } + + if (ModuleUIGenerator.UI_EDIT == genType) { + targetTemplate = templatesDir + templates[2]; + targetOutputDir = htmlOutputDir; + targetOutputDirFile = targetOutputDir + File.separator + tableMeta.name + "_edit.html"; + } + if (ModuleUIGenerator.UI_LIST == genType) { + targetTemplate = templatesDir + templates[3]; + targetOutputDir = htmlOutputDir; + targetOutputDirFile = targetOutputDir + File.separator + tableMeta.name + "_list.html"; + } + // tableMeta.columnMetas.get(0).remarks + String content = engine.getTemplate(targetTemplate).renderToString(data); + + // + File dir = new File(targetOutputDir); + if (!dir.exists()) { + dir.mkdirs(); + } + File targetFile = new File(targetOutputDirFile); + if (targetFile.exists()) { + return; + } + try { + FileWriter fw = new FileWriter(targetOutputDirFile); + try { + fw.write(content); + } finally { + fw.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + +} diff --git a/codegen/src/main/java/io/jpress/codegen/generator/ServiceApiGenerator.java b/codegen/src/main/java/io/jpress/codegen/generator/ServiceApiGenerator.java index dcc8f2531fd26bbdd062294a80c8e50757b1e852..63c815a6e967a248295edcf8b9e6058dd39fa9df 100644 --- a/codegen/src/main/java/io/jpress/codegen/generator/ServiceApiGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/generator/ServiceApiGenerator.java @@ -1,117 +1,117 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen.generator; - -import com.jfinal.kit.Kv; -import com.jfinal.kit.StrKit; -import com.jfinal.plugin.activerecord.generator.BaseModelGenerator; -import com.jfinal.plugin.activerecord.generator.TableMeta; -import com.jfinal.template.Engine; -import com.jfinal.template.source.ClassPathSourceFactory; -import io.jboot.app.JbootApplication; -import io.jboot.codegen.CodeGenHelpler; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.List; - -public class ServiceApiGenerator extends BaseModelGenerator { - - private String modelPacket; - private String basePackage; - - public static void main(String[] args) { - - JbootApplication.setBootArg("jboot.datasource.url", "jdbc:mysql://127.0.0.1:3306/jbootdemo"); - JbootApplication.setBootArg("jboot.datasource.user", "root"); - - String basePackage = "io.jboot.codegen.service.test"; - String modelPackage = "io.jboot.codegen.model.test"; - - List tableMetaList = CodeGenHelpler.createMetaBuilder().build(); - CodeGenHelpler.excludeTables(tableMetaList, null); - - new ServiceApiGenerator(basePackage, modelPackage,"core-service").generate(tableMetaList); - } - - public ServiceApiGenerator(String basePackage, String modelPacket, String baseModelOutputDir) { - super(basePackage, baseModelOutputDir); - - - this.modelPacket = modelPacket; - this.basePackage = basePackage; - this.template = "io/jpress/codegen/templates/service_template.jf"; - - } - - @Override - public void generate(List tableMetas) { - System.out.println("Generate base model ..."); - System.out.println("Base Model Output Dir: " + baseModelOutputDir); - - Engine engine = Engine.create("forService"); - engine.setSourceFactory(new ClassPathSourceFactory()); - engine.addSharedMethod(new StrKit()); - engine.addSharedObject("getterTypeMap", getterTypeMap); - engine.addSharedObject("javaKeyword", javaKeyword); - - for (TableMeta tableMeta : tableMetas) { - genBaseModelContent(tableMeta); - } - writeToFile(tableMetas); - } - - @Override - protected void genBaseModelContent(TableMeta tableMeta) { - Kv data = Kv.by("baseModelPackageName", baseModelPackageName); - data.set("generateChainSetter", generateChainSetter); - data.set("tableMeta", tableMeta); - data.set("modelPacket", modelPacket); - data.set("basePackage", basePackage); - - Engine engine = Engine.use("forService"); - tableMeta.baseModelContent = engine.getTemplate(template).renderToString(data); - } - - - /** - * base model 覆盖写入 - */ - @Override - protected void writeToFile(TableMeta tableMeta) throws IOException { - File dir = new File(baseModelOutputDir); - if (!dir.exists()) { - dir.mkdirs(); - } - - String target = baseModelOutputDir + File.separator + tableMeta.modelName + "Service" + ".java"; - - File targetFile = new File(target); - if (targetFile.exists()) { - return; - } - - FileWriter fw = new FileWriter(target); - try { - fw.write(tableMeta.baseModelContent); - } finally { - fw.close(); - } - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen.generator; + +import com.jfinal.kit.Kv; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.generator.BaseModelGenerator; +import com.jfinal.plugin.activerecord.generator.TableMeta; +import com.jfinal.template.Engine; +import com.jfinal.template.source.ClassPathSourceFactory; +import io.jboot.app.JbootApplication; +import io.jboot.codegen.CodeGenHelpler; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +public class ServiceApiGenerator extends BaseModelGenerator { + + private String modelPacket; + private String basePackage; + + public static void main(String[] args) { + + JbootApplication.setBootArg("jboot.datasource.url", "jdbc:mysql://127.0.0.1:3306/jbootdemo"); + JbootApplication.setBootArg("jboot.datasource.user", "root"); + + String basePackage = "io.jboot.codegen.service.test"; + String modelPackage = "io.jboot.codegen.model.test"; + + List tableMetaList = CodeGenHelpler.createMetaBuilder().build(); + CodeGenHelpler.excludeTables(tableMetaList, null); + + new ServiceApiGenerator(basePackage, modelPackage,"core-service").generate(tableMetaList); + } + + public ServiceApiGenerator(String basePackage, String modelPacket, String baseModelOutputDir) { + super(basePackage, baseModelOutputDir); + + + this.modelPacket = modelPacket; + this.basePackage = basePackage; + this.template = "io/jpress/codegen/templates/service_template.jf"; + + } + + @Override + public void generate(List tableMetas) { + System.out.println("Generate base model ..."); + System.out.println("Base Model Output Dir: " + baseModelOutputDir); + + Engine engine = Engine.create("forService"); + engine.setSourceFactory(new ClassPathSourceFactory()); + engine.addSharedMethod(new StrKit()); + engine.addSharedObject("getterTypeMap", getterTypeMap); + engine.addSharedObject("javaKeyword", javaKeyword); + + for (TableMeta tableMeta : tableMetas) { + genBaseModelContent(tableMeta); + } + writeToFile(tableMetas); + } + + @Override + protected void genBaseModelContent(TableMeta tableMeta) { + Kv data = Kv.by("baseModelPackageName", baseModelPackageName); + data.set("generateChainSetter", generateChainSetter); + data.set("tableMeta", tableMeta); + data.set("modelPacket", modelPacket); + data.set("basePackage", basePackage); + + Engine engine = Engine.use("forService"); + tableMeta.baseModelContent = engine.getTemplate(template).renderToString(data); + } + + + /** + * base model 覆盖写入 + */ + @Override + protected void writeToFile(TableMeta tableMeta) throws IOException { + File dir = new File(baseModelOutputDir); + if (!dir.exists()) { + dir.mkdirs(); + } + + String target = baseModelOutputDir + File.separator + tableMeta.modelName + "Service" + ".java"; + + File targetFile = new File(target); + if (targetFile.exists()) { + return; + } + + FileWriter fw = new FileWriter(target); + try { + fw.write(tableMeta.baseModelContent); + } finally { + fw.close(); + } + } + + +} diff --git a/codegen/src/main/java/io/jpress/codegen/generator/ServiceProviderGenerator.java b/codegen/src/main/java/io/jpress/codegen/generator/ServiceProviderGenerator.java index be54d4bced629414ee92834a08f7fee136021103..5c614bfd930dac0a482b7ff2e10550062f7f812b 100644 --- a/codegen/src/main/java/io/jpress/codegen/generator/ServiceProviderGenerator.java +++ b/codegen/src/main/java/io/jpress/codegen/generator/ServiceProviderGenerator.java @@ -1,100 +1,100 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.codegen.generator; - -import com.jfinal.kit.Kv; -import com.jfinal.kit.StrKit; -import com.jfinal.plugin.activerecord.generator.BaseModelGenerator; -import com.jfinal.plugin.activerecord.generator.TableMeta; -import com.jfinal.template.Engine; -import com.jfinal.template.source.ClassPathSourceFactory; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.List; - -public class ServiceProviderGenerator extends BaseModelGenerator { - - String basePackage; - String modelPackage; - - public ServiceProviderGenerator(String basePackage, String modelPackage, String baseModelOutputDir) { - super(basePackage + ".provider", baseModelOutputDir); - - this.basePackage = basePackage; - this.modelPackage = modelPackage; - this.template = "io/jpress/codegen/templates/service_provider_template.jf"; - - - } - - @Override - public void generate(List tableMetas) { - System.out.println("Generate base model ..."); - System.out.println("Base Model Output Dir: " + baseModelOutputDir); - - Engine engine = Engine.create("forServiceImpl"); - engine.setSourceFactory(new ClassPathSourceFactory()); - engine.addSharedMethod(new StrKit()); - engine.addSharedObject("getterTypeMap", getterTypeMap); - engine.addSharedObject("javaKeyword", javaKeyword); - - for (TableMeta tableMeta : tableMetas) { - genBaseModelContent(tableMeta); - } - writeToFile(tableMetas); - } - - - @Override - protected void genBaseModelContent(TableMeta tableMeta) { - Kv data = Kv.by("serviceImplPackageName", baseModelPackageName); - data.set("generateChainSetter", generateChainSetter); - data.set("tableMeta", tableMeta); - data.set("basePackage", basePackage); - data.set("modelPackage", modelPackage); - - Engine engine = Engine.use("forServiceImpl"); - tableMeta.baseModelContent = engine.getTemplate(template).renderToString(data); - } - - /** - * base model 覆盖写入 - */ - @Override - protected void writeToFile(TableMeta tableMeta) throws IOException { - File dir = new File(baseModelOutputDir); - if (!dir.exists()) { - dir.mkdirs(); - } - - String target = baseModelOutputDir + File.separator + tableMeta.modelName + "ServiceProvider" + ".java"; - - File targetFile = new File(target); - if (targetFile.exists()) { - return; - } - - - FileWriter fw = new FileWriter(target); - try { - fw.write(tableMeta.baseModelContent); - } finally { - fw.close(); - } - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.codegen.generator; + +import com.jfinal.kit.Kv; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.generator.BaseModelGenerator; +import com.jfinal.plugin.activerecord.generator.TableMeta; +import com.jfinal.template.Engine; +import com.jfinal.template.source.ClassPathSourceFactory; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +public class ServiceProviderGenerator extends BaseModelGenerator { + + String basePackage; + String modelPackage; + + public ServiceProviderGenerator(String basePackage, String modelPackage, String baseModelOutputDir) { + super(basePackage + ".provider", baseModelOutputDir); + + this.basePackage = basePackage; + this.modelPackage = modelPackage; + this.template = "io/jpress/codegen/templates/service_provider_template.jf"; + + + } + + @Override + public void generate(List tableMetas) { + System.out.println("Generate base model ..."); + System.out.println("Base Model Output Dir: " + baseModelOutputDir); + + Engine engine = Engine.create("forServiceImpl"); + engine.setSourceFactory(new ClassPathSourceFactory()); + engine.addSharedMethod(new StrKit()); + engine.addSharedObject("getterTypeMap", getterTypeMap); + engine.addSharedObject("javaKeyword", javaKeyword); + + for (TableMeta tableMeta : tableMetas) { + genBaseModelContent(tableMeta); + } + writeToFile(tableMetas); + } + + + @Override + protected void genBaseModelContent(TableMeta tableMeta) { + Kv data = Kv.by("serviceImplPackageName", baseModelPackageName); + data.set("generateChainSetter", generateChainSetter); + data.set("tableMeta", tableMeta); + data.set("basePackage", basePackage); + data.set("modelPackage", modelPackage); + + Engine engine = Engine.use("forServiceImpl"); + tableMeta.baseModelContent = engine.getTemplate(template).renderToString(data); + } + + /** + * base model 覆盖写入 + */ + @Override + protected void writeToFile(TableMeta tableMeta) throws IOException { + File dir = new File(baseModelOutputDir); + if (!dir.exists()) { + dir.mkdirs(); + } + + String target = baseModelOutputDir + File.separator + tableMeta.modelName + "ServiceProvider" + ".java"; + + File targetFile = new File(target); + if (targetFile.exists()) { + return; + } + + + FileWriter fw = new FileWriter(target); + try { + fw.write(tableMeta.baseModelContent); + } finally { + fw.close(); + } + } +} diff --git a/codegen/src/main/java/io/jpress/codegen/templates/base_model_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/base_model_template.jf index 170ddf95090d76374c8c02c63b8eedf00e316e3f..5524a9dd52ebcec98c9089c0b60ebabfd25f99b8 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/base_model_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/base_model_template.jf @@ -1,48 +1,48 @@ -package #(baseModelPackageName); - -import io.jboot.db.model.JbootModel; -import com.jfinal.plugin.activerecord.IBean; - -/** - * Generated by JPress, do not modify this file. - */ -#if (generateChainSetter) -@SuppressWarnings({"serial", "unchecked"}) -#else -@SuppressWarnings("serial") -#end -public abstract class #(tableMeta.baseModelName)> extends JbootModel implements IBean { - - private static final long serialVersionUID = 1L; - -#set(b = generateChainSetter) -#for(cm : tableMeta.columnMetas) - #if (cm.remarks) - /** - * #(cm.remarks) - */ - #end - #set(argName = javaKeyword.contains(cm.attrName) ? '_' + cm.attrName : cm.attrName) - public #(b ? 'M' : 'void') set#(firstCharToUpperCase(cm.attrName))(#(cm.javaType) #(argName)) { - set("#(cm.name)", #(argName)); - #if(b) - return (M)this; - #end - } - - #if (cm.remarks) - /** - * #(cm.remarks) - */ - #end - #set(getterOfModel = getterTypeMap.get(cm.javaType)) - #if(isBlank(getterOfModel)) - #set(getterOfModel = 'get') - #end - public #(cm.javaType) get#(firstCharToUpperCase(cm.attrName))() { - return #(getterOfModel)("#(cm.name)"); - } - -#end -} - +package #(baseModelPackageName); + +import io.jboot.db.model.JbootModel; +import com.jfinal.plugin.activerecord.IBean; + +/** + * Generated by JPress, do not modify this file. + */ +#if (generateChainSetter) +@SuppressWarnings({"serial", "unchecked"}) +#else +@SuppressWarnings("serial") +#end +public abstract class #(tableMeta.baseModelName)> extends JbootModel implements IBean { + + private static final long serialVersionUID = 1L; + +#set(b = generateChainSetter) +#for(cm : tableMeta.columnMetas) + #if (cm.remarks) + /** + * #(cm.remarks) + */ + #end + #set(argName = javaKeyword.contains(cm.attrName) ? '_' + cm.attrName : cm.attrName) + public #(b ? 'M' : 'void') set#(firstCharToUpperCase(cm.attrName))(#(cm.javaType) #(argName)) { + set("#(cm.name)", #(argName)); + #if(b) + return (M)this; + #end + } + + #if (cm.remarks) + /** + * #(cm.remarks) + */ + #end + #set(getterOfModel = getterTypeMap.get(cm.javaType)) + #if(isBlank(getterOfModel)) + #set(getterOfModel = 'get') + #end + public #(cm.javaType) get#(firstCharToUpperCase(cm.attrName))() { + return #(getterOfModel)("#(cm.name)"); + } + +#end +} + diff --git a/codegen/src/main/java/io/jpress/codegen/templates/base_options_model_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/base_options_model_template.jf index 09099808f083e24ca31dec0a65d6b9b8c31af7a5..881a9e71731ce94abd5ccfa9e47ff81ff6828872 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/base_options_model_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/base_options_model_template.jf @@ -1,48 +1,48 @@ -package #(baseModelPackageName); - -import com.jfinal.plugin.activerecord.IBean; -import io.jpress.base.BaseOptionsModel; - -/** - * Generated by JPress, do not modify this file. - */ -#if (generateChainSetter) -@SuppressWarnings({"serial", "unchecked"}) -#else -@SuppressWarnings("serial") -#end -public abstract class #(tableMeta.baseModelName)> extends BaseOptionsModel implements IBean { - - private static final long serialVersionUID = 1L; - -#set(b = generateChainSetter) -#for(cm : tableMeta.columnMetas) - #if (cm.remarks) - /** - * #(cm.remarks) - */ - #end - #set(argName = javaKeyword.contains(cm.attrName) ? '_' + cm.attrName : cm.attrName) - public #(b ? 'M' : 'void') set#(firstCharToUpperCase(cm.attrName))(#(cm.javaType) #(argName)) { - set("#(cm.name)", #(argName)); - #if(b) - return (M)this; - #end - } - - #if (cm.remarks) - /** - * #(cm.remarks) - */ - #end - #set(getterOfModel = getterTypeMap.get(cm.javaType)) - #if(isBlank(getterOfModel)) - #set(getterOfModel = 'get') - #end - public #(cm.javaType) get#(firstCharToUpperCase(cm.attrName))() { - return #(getterOfModel)("#(cm.name)"); - } - -#end -} - +package #(baseModelPackageName); + +import com.jfinal.plugin.activerecord.IBean; +import io.jpress.base.BaseOptionsModel; + +/** + * Generated by JPress, do not modify this file. + */ +#if (generateChainSetter) +@SuppressWarnings({"serial", "unchecked"}) +#else +@SuppressWarnings("serial") +#end +public abstract class #(tableMeta.baseModelName)> extends BaseOptionsModel implements IBean { + + private static final long serialVersionUID = 1L; + +#set(b = generateChainSetter) +#for(cm : tableMeta.columnMetas) + #if (cm.remarks) + /** + * #(cm.remarks) + */ + #end + #set(argName = javaKeyword.contains(cm.attrName) ? '_' + cm.attrName : cm.attrName) + public #(b ? 'M' : 'void') set#(firstCharToUpperCase(cm.attrName))(#(cm.javaType) #(argName)) { + set("#(cm.name)", #(argName)); + #if(b) + return (M)this; + #end + } + + #if (cm.remarks) + /** + * #(cm.remarks) + */ + #end + #set(getterOfModel = getterTypeMap.get(cm.javaType)) + #if(isBlank(getterOfModel)) + #set(getterOfModel = 'get') + #end + public #(cm.javaType) get#(firstCharToUpperCase(cm.attrName))() { + return #(getterOfModel)("#(cm.name)"); + } + +#end +} + diff --git a/codegen/src/main/java/io/jpress/codegen/templates/model_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/model_template.jf index 3563e85c51b4a99d96ade257e51a929afd992c02..b3ea2bfd7b6d3d359ab8f1b8ccafe355ea67dce3 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/model_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/model_template.jf @@ -1,20 +1,20 @@ -package #(modelPackageName); - -import io.jboot.db.annotation.Table; -import #(baseModelPackageName).#(tableMeta.baseModelName); - -/** - * Generated by JPress. - */ -@Table(tableName = "#(tableMeta.name)", primaryKey = "#(tableMeta.primaryKey)") -public class #(tableMeta.modelName) extends #(tableMeta.baseModelName)<#(tableMeta.modelName)> { - - private static final long serialVersionUID = 1L; - - #if(generateDaoInModel) - public static final #(tableMeta.modelName) dao = new #(tableMeta.modelName)().dao(); - #else - - #end -} - +package #(modelPackageName); + +import io.jboot.db.annotation.Table; +import #(baseModelPackageName).#(tableMeta.baseModelName); + +/** + * Generated by JPress. + */ +@Table(tableName = "#(tableMeta.name)", primaryKey = "#(tableMeta.primaryKey)") +public class #(tableMeta.modelName) extends #(tableMeta.baseModelName)<#(tableMeta.modelName)> { + + private static final long serialVersionUID = 1L; + + #if(generateDaoInModel) + public static final #(tableMeta.modelName) dao = new #(tableMeta.modelName)().dao(); + #else + + #end +} + diff --git a/codegen/src/main/java/io/jpress/codegen/templates/module_listener_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/module_listener_template.jf index e449d2fe5ac3c98c431e9ab905e936c4d13f9f1c..85d644ffffb383493661383c542dc000307e8e8a 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/module_listener_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/module_listener_template.jf @@ -1,62 +1,62 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.module.#(moduleName); - -import com.jfinal.core.Controller; -import io.jboot.Jboot; -import io.jboot.core.listener.JbootAppListenerBase; -import io.jboot.db.model.Columns; -import io.jpress.core.menu.MenuGroup; -import io.jpress.core.module.ModuleListener; -import java.util.List; - -/** - * @version V1.0 - * @Title: Module 监听器 - * @Description: 每个 module 都应该有这样的一个监听器,用来配置自身Module的信息,比如后台菜单等 - * @Package io.jpress.module.#(moduleName) - */ -public class #(upcasedModuleName)ModuleInitializer extends JbootAppListenerBase implements ModuleListener { - - - @Override - public String onRenderDashboardBox(Controller controller) { - return null; - } - - @Override - public String onRenderToolsBox(Controller controller) { - return null; - } - - @Override - public void onConfigAdminMenu(List adminMenus) { - MenuGroup menuGroup = new MenuGroup(); - menuGroup.setId("#(moduleName)"); - menuGroup.setText("#(moduleName)"); - menuGroup.setIcon(""); - menuGroup.setOrder(1); - adminMenus.add(menuGroup); - } - - @Override - public void onConfigUcenterMenu(List ucenterMenus) { - - - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.module.#(moduleName); + +import com.jfinal.core.Controller; +import io.jboot.Jboot; +import io.jboot.core.listener.JbootAppListenerBase; +import io.jboot.db.model.Columns; +import io.jpress.core.menu.MenuGroup; +import io.jpress.core.module.ModuleListener; +import java.util.List; + +/** + * @version V1.0 + * @Title: Module 监听器 + * @Description: 每个 module 都应该有这样的一个监听器,用来配置自身Module的信息,比如后台菜单等 + * @Package io.jpress.module.#(moduleName) + */ +public class #(upcasedModuleName)ModuleInitializer extends JbootAppListenerBase implements ModuleListener { + + + @Override + public String onRenderDashboardBox(Controller controller) { + return null; + } + + @Override + public String onRenderToolsBox(Controller controller) { + return null; + } + + @Override + public void onConfigAdminMenu(List adminMenus) { + MenuGroup menuGroup = new MenuGroup(); + menuGroup.setId("#(moduleName)"); + menuGroup.setText("#(moduleName)"); + menuGroup.setIcon(""); + menuGroup.setOrder(1); + adminMenus.add(menuGroup); + } + + @Override + public void onConfigUcenterMenu(List ucenterMenus) { + + + } + + +} diff --git a/codegen/src/main/java/io/jpress/codegen/templates/pom_model_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/pom_model_template.jf index 90e841d09240e6ec0915c4ce726caa3031235325..9e2989139ded47bf5c745bbf3fc497578b6feae7 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/pom_model_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/pom_model_template.jf @@ -1,23 +1,23 @@ - - - - io.jpress - module-#(moduleName) - 2.0 - - 4.0.0 - - io.jpress - module-#(moduleName)-model - - - - io.jboot - jboot - - - - + + + + io.jpress + module-#(moduleName) + 2.0 + + 4.0.0 + + io.jpress + module-#(moduleName)-model + + + + io.jboot + jboot + + + + \ No newline at end of file diff --git a/codegen/src/main/java/io/jpress/codegen/templates/pom_module_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/pom_module_template.jf index 7908069cd681b1040e62ccb2b39f535f984b3feb..8f80b924a7bec36334a8ec47fa0c1625f4640d77 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/pom_module_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/pom_module_template.jf @@ -1,43 +1,43 @@ - - - - io.jpress - parent - 2.0 - - 4.0.0 - - pom - 2.0 - - io.jpress - module-#(moduleName) - - - 1.8 - 1.8 - - - - module-#(moduleName)-model - module-#(moduleName)-web - module-#(moduleName)-service-api - module-#(moduleName)-service-provider - - - - - - org.codehaus.mojo - versions-maven-plugin - 2.7 - - false - - - - - + + + + io.jpress + parent + 2.0 + + 4.0.0 + + pom + 2.0 + + io.jpress + module-#(moduleName) + + + 1.8 + 1.8 + + + + module-#(moduleName)-model + module-#(moduleName)-web + module-#(moduleName)-service-api + module-#(moduleName)-service-provider + + + + + + org.codehaus.mojo + versions-maven-plugin + 2.7 + + false + + + + + \ No newline at end of file diff --git a/codegen/src/main/java/io/jpress/codegen/templates/pom_service_api_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/pom_service_api_template.jf index cce4ab3b2c5902a1f30d30dbb9f392a9174b8955..0a8e91c5eff6019364f0d132f35f0df0bc466fe5 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/pom_service_api_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/pom_service_api_template.jf @@ -1,31 +1,31 @@ - - - - io.jpress - module-#(moduleName) - 2.0 - - 4.0.0 - - io.jpress - module-#(moduleName)-service-api - - - - io.jboot - jboot - - - - io.jpress - module-#(moduleName)-model - 2.0 - - - - - - + + + + io.jpress + module-#(moduleName) + 2.0 + + 4.0.0 + + io.jpress + module-#(moduleName)-service-api + + + + io.jboot + jboot + + + + io.jpress + module-#(moduleName)-model + 2.0 + + + + + + \ No newline at end of file diff --git a/codegen/src/main/java/io/jpress/codegen/templates/pom_service_provider_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/pom_service_provider_template.jf index de5cb4818c054bdc66ad41081ebec405eade0ce9..f639be6329fd20cdee661a2ba827e5c72e6ed99d 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/pom_service_provider_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/pom_service_provider_template.jf @@ -1,42 +1,42 @@ - - - - io.jpress - module-#(moduleName) - 2.0 - - 4.0.0 - - io.jpress - module-#(moduleName)-service-provider - - - - - io.jboot - jboot - - - - io.jpress - jpress-core - - - - io.jpress - module-#(moduleName)-model - 2.0 - - - - io.jpress - module-#(moduleName)-service-api - 2.0 - - - - - + + + + io.jpress + module-#(moduleName) + 2.0 + + 4.0.0 + + io.jpress + module-#(moduleName)-service-provider + + + + + io.jboot + jboot + + + + io.jpress + jpress-core + + + + io.jpress + module-#(moduleName)-model + 2.0 + + + + io.jpress + module-#(moduleName)-service-api + 2.0 + + + + + \ No newline at end of file diff --git a/codegen/src/main/java/io/jpress/codegen/templates/pom_web_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/pom_web_template.jf index 09d423e1645a41518452f25d5630b29f90204c1a..011854f8eb50509625ea53e6abf4a877d229a4e4 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/pom_web_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/pom_web_template.jf @@ -1,47 +1,47 @@ - - - - io.jpress - module-#(moduleName) - 2.0 - - 4.0.0 - - io.jpress - module-#(moduleName)-web - - - - - io.jboot - jboot - - - - io.jpress - jpress-core - - - - io.jpress - module-#(moduleName)-model - 2.0 - - - - io.jpress - module-#(moduleName)-service-api - 2.0 - - - - io.jpress - module-#(moduleName)-service-provider - 2.0 - - - - + + + + io.jpress + module-#(moduleName) + 2.0 + + 4.0.0 + + io.jpress + module-#(moduleName)-web + + + + + io.jboot + jboot + + + + io.jpress + jpress-core + + + + io.jpress + module-#(moduleName)-model + 2.0 + + + + io.jpress + module-#(moduleName)-service-api + 2.0 + + + + io.jpress + module-#(moduleName)-service-provider + 2.0 + + + + \ No newline at end of file diff --git a/codegen/src/main/java/io/jpress/codegen/templates/service_provider_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/service_provider_template.jf index 8cb6ccb11bf033e059f2800aa31ea4f1f45455e1..20080be2b59958e5dd2dfea4d11bc4aa9bfc89a3 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/service_provider_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/service_provider_template.jf @@ -1,11 +1,11 @@ -package #(serviceImplPackageName); - -import io.jboot.aop.annotation.Bean; -import #(basePackage).#(tableMeta.modelName)Service; -import #(modelPackage).#(tableMeta.modelName); -import io.jboot.service.JbootServiceBase; - -@Bean -public class #(tableMeta.modelName)ServiceProvider extends JbootServiceBase<#(tableMeta.modelName)> implements #(tableMeta.modelName)Service { - +package #(serviceImplPackageName); + +import io.jboot.aop.annotation.Bean; +import #(basePackage).#(tableMeta.modelName)Service; +import #(modelPackage).#(tableMeta.modelName); +import io.jboot.service.JbootServiceBase; + +@Bean +public class #(tableMeta.modelName)ServiceProvider extends JbootServiceBase<#(tableMeta.modelName)> implements #(tableMeta.modelName)Service { + } \ No newline at end of file diff --git a/codegen/src/main/java/io/jpress/codegen/templates/service_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/service_template.jf index f720a7a684c683e0dc77353af9c79def12b597a3..f0a324c0987f55e2cd579376df05266285f1d113 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/service_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/service_template.jf @@ -1,178 +1,178 @@ -package #(basePackage); - -import com.jfinal.plugin.activerecord.Page; -import #(modelPacket).#(tableMeta.modelName); -import io.jboot.db.model.Columns; - -import java.util.List; - -public interface #(tableMeta.modelName)Service { - - /** - * 根据主键查找Model - * - * @param id - * @return - */ - public #(tableMeta.modelName) findById(Object id); - - - /** - * 根据 Columns 查找单条数据 - * - * @param columns - * @return - */ - public #(tableMeta.modelName) findFirstByColumns(Columns columns); - - /** - * 根据 Columns 查找单条数据 - * - * @param columns - * @param orderBy - * @return - */ - public #(tableMeta.modelName) findFirstByColumns(Columns columns, String orderBy); - - - /** - * 查找全部数据 - * - * @return - */ - public List<#(tableMeta.modelName)> findAll(); - - - /** - * 根据 Columns 查找数据 - * - * @param columns - * @return - */ - public List<#(tableMeta.modelName)> findListByColumns(Columns columns); - - - /** - * 根据 Columns 查找数据 - * - * @param columns - * @param orderBy - * @return - */ - public List<#(tableMeta.modelName)> findListByColumns(Columns columns, String orderBy); - - /** - * 根据 Columns 查找数据 - * - * @param columns - * @param count - * @return - */ - public List<#(tableMeta.modelName)> findListByColumns(Columns columns, Integer count); - - /** - * 根据 Columns 查找数据 - * - * @param columns - * @param orderBy - * @param count - * @return - */ - public List<#(tableMeta.modelName)> findListByColumns(Columns columns, String orderBy, Integer count); - - - /** - * 根据提交查询数据量 - * - * @param columns - * @return - */ - public long findCountByColumns(Columns columns); - - - /** - * 根据ID 删除model - * - * @param id - * @return - */ - public boolean deleteById(Object id); - - - /** - * 删除 - * - * @param model - * @return - */ - public boolean delete(#(tableMeta.modelName) model); - - - /** - * 根据 多个 id 批量删除 - * - * @param ids - * @return - */ - public boolean batchDeleteByIds(Object... ids); - - - /** - * 保存到数据库 - * - * @param model - * @return id if success - */ - public Object save(#(tableMeta.modelName) model); - - - /** - * 保存或更新 - * - * @param model - * @return id if success - */ - public Object saveOrUpdate(#(tableMeta.modelName) model); - - /** - * 更新 - * - * @param model - * @return - */ - public boolean update(#(tableMeta.modelName) model); - - - /** - * 分页 - * - * @param page - * @param pageSize - * @return - */ - public Page<#(tableMeta.modelName)> paginate(int page, int pageSize); - - - /** - * 分页 - * - * @param page - * @param pageSize - * @return - */ - public Page<#(tableMeta.modelName)> paginateByColumns(int page, int pageSize, Columns columns); - - - /** - * 分页 - * - * @param page - * @param pageSize - * @param columns - * @param orderBy - * @return - */ - public Page<#(tableMeta.modelName)> paginateByColumns(int page, int pageSize, Columns columns, String orderBy); - - +package #(basePackage); + +import com.jfinal.plugin.activerecord.Page; +import #(modelPacket).#(tableMeta.modelName); +import io.jboot.db.model.Columns; + +import java.util.List; + +public interface #(tableMeta.modelName)Service { + + /** + * 根据主键查找Model + * + * @param id + * @return + */ + public #(tableMeta.modelName) findById(Object id); + + + /** + * 根据 Columns 查找单条数据 + * + * @param columns + * @return + */ + public #(tableMeta.modelName) findFirstByColumns(Columns columns); + + /** + * 根据 Columns 查找单条数据 + * + * @param columns + * @param orderBy + * @return + */ + public #(tableMeta.modelName) findFirstByColumns(Columns columns, String orderBy); + + + /** + * 查找全部数据 + * + * @return + */ + public List<#(tableMeta.modelName)> findAll(); + + + /** + * 根据 Columns 查找数据 + * + * @param columns + * @return + */ + public List<#(tableMeta.modelName)> findListByColumns(Columns columns); + + + /** + * 根据 Columns 查找数据 + * + * @param columns + * @param orderBy + * @return + */ + public List<#(tableMeta.modelName)> findListByColumns(Columns columns, String orderBy); + + /** + * 根据 Columns 查找数据 + * + * @param columns + * @param count + * @return + */ + public List<#(tableMeta.modelName)> findListByColumns(Columns columns, Integer count); + + /** + * 根据 Columns 查找数据 + * + * @param columns + * @param orderBy + * @param count + * @return + */ + public List<#(tableMeta.modelName)> findListByColumns(Columns columns, String orderBy, Integer count); + + + /** + * 根据提交查询数据量 + * + * @param columns + * @return + */ + public long findCountByColumns(Columns columns); + + + /** + * 根据ID 删除model + * + * @param id + * @return + */ + public boolean deleteById(Object id); + + + /** + * 删除 + * + * @param model + * @return + */ + public boolean delete(#(tableMeta.modelName) model); + + + /** + * 根据 多个 id 批量删除 + * + * @param ids + * @return + */ + public boolean batchDeleteByIds(Object... ids); + + + /** + * 保存到数据库 + * + * @param model + * @return id if success + */ + public Object save(#(tableMeta.modelName) model); + + + /** + * 保存或更新 + * + * @param model + * @return id if success + */ + public Object saveOrUpdate(#(tableMeta.modelName) model); + + /** + * 更新 + * + * @param model + * @return + */ + public boolean update(#(tableMeta.modelName) model); + + + /** + * 分页 + * + * @param page + * @param pageSize + * @return + */ + public Page<#(tableMeta.modelName)> paginate(int page, int pageSize); + + + /** + * 分页 + * + * @param page + * @param pageSize + * @return + */ + public Page<#(tableMeta.modelName)> paginateByColumns(int page, int pageSize, Columns columns); + + + /** + * 分页 + * + * @param page + * @param pageSize + * @param columns + * @param orderBy + * @return + */ + public Page<#(tableMeta.modelName)> paginateByColumns(int page, int pageSize, Columns columns, String orderBy); + + } \ No newline at end of file diff --git a/codegen/src/main/java/io/jpress/codegen/templates/ui_controller_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/ui_controller_template.jf index a7bb71617b0b3e5309a8fc04ced3b9b699af8129..673cebda00ff8300e4abb6b8d82005748d97e380 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/ui_controller_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/ui_controller_template.jf @@ -1,72 +1,72 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package #(controllerPackage); - -import com.jfinal.aop.Inject; -import com.jfinal.kit.Ret; -import com.jfinal.plugin.activerecord.Page; -import io.jboot.web.controller.annotation.RequestMapping; -import io.jboot.web.validate.EmptyValidate; -import io.jpress.JPressConsts; -import io.jpress.core.menu.annotation.AdminMenu; -import #(modelPackage).#(tableMeta.modelName); -import #(modulePackage).service.#(tableMeta.modelName)Service; -import io.jpress.web.base.AdminControllerBase; -import java.util.Date; - - -@RequestMapping(value = "/admin/#(moduleName)/#(tableMeta.name)", viewPath = JPressConsts.DEFAULT_ADMIN_VIEW) -public class _#(tableMeta.modelName)Controller extends AdminControllerBase { - - @Inject - private #(tableMeta.modelName)Service service; - - @AdminMenu(text = "#(tableMeta.remarks)管理", groupId = "#(moduleName)") - public void index() { - Page<#(tableMeta.modelName)> entries=service.paginate(getPagePara(), 10); - setAttr("page", entries); - render("#(moduleName)/#(tableMeta.name)_list.html"); - } - - - public void edit() { - int entryId = getParaToInt(0, 0); - - #(tableMeta.modelName) entry = entryId > 0 ? service.findById(entryId) : null; - setAttr("#(lowerCaseModelName)", entry); - set("now",new Date()); - render("#(moduleName)/#(tableMeta.name)_edit.html"); - } - - public void doSave() { - #(tableMeta.modelName) entry = getModel(#(tableMeta.modelName).class,"#(firstCharToLowerCase(tableMeta.modelName))"); - service.saveOrUpdate(entry); - renderJson(Ret.ok().set("id", entry.getId())); - } - - - public void doDel() { - Long id = getIdPara(); - render(service.deleteById(id) ? Ret.ok() : Ret.fail()); - } - - @EmptyValidate(@Form(name = "ids")) - public void doDelByIds() { - service.batchDeleteByIds(getParaSet("ids").toArray()); - renderOkJson(); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package #(controllerPackage); + +import com.jfinal.aop.Inject; +import com.jfinal.kit.Ret; +import com.jfinal.plugin.activerecord.Page; +import io.jboot.web.controller.annotation.RequestMapping; +import io.jboot.web.validate.EmptyValidate; +import io.jpress.JPressConsts; +import io.jpress.core.menu.annotation.AdminMenu; +import #(modelPackage).#(tableMeta.modelName); +import #(modulePackage).service.#(tableMeta.modelName)Service; +import io.jpress.web.base.AdminControllerBase; +import java.util.Date; + + +@RequestMapping(value = "/admin/#(moduleName)/#(tableMeta.name)", viewPath = JPressConsts.DEFAULT_ADMIN_VIEW) +public class _#(tableMeta.modelName)Controller extends AdminControllerBase { + + @Inject + private #(tableMeta.modelName)Service service; + + @AdminMenu(text = "#(tableMeta.remarks)管理", groupId = "#(moduleName)") + public void index() { + Page<#(tableMeta.modelName)> entries=service.paginate(getPagePara(), 10); + setAttr("page", entries); + render("#(moduleName)/#(tableMeta.name)_list.html"); + } + + + public void edit() { + int entryId = getParaToInt(0, 0); + + #(tableMeta.modelName) entry = entryId > 0 ? service.findById(entryId) : null; + setAttr("#(lowerCaseModelName)", entry); + set("now",new Date()); + render("#(moduleName)/#(tableMeta.name)_edit.html"); + } + + public void doSave() { + #(tableMeta.modelName) entry = getModel(#(tableMeta.modelName).class,"#(firstCharToLowerCase(tableMeta.modelName))"); + service.saveOrUpdate(entry); + renderJson(Ret.ok().set("id", entry.getId())); + } + + + public void doDel() { + Long id = getIdPara(); + render(service.deleteById(id) ? Ret.ok() : Ret.fail()); + } + + @EmptyValidate(@Form(name = "ids")) + public void doDelByIds() { + service.batchDeleteByIds(getParaSet("ids").toArray()); + renderOkJson(); + } + +} diff --git a/codegen/src/main/java/io/jpress/codegen/templates/ui_controller_template_for_addon.jf b/codegen/src/main/java/io/jpress/codegen/templates/ui_controller_template_for_addon.jf index 2c8eb3aee1bf367651e837ea6428768764161b6a..2bbb564149e46a10056812bb7224d1c4725a25ad 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/ui_controller_template_for_addon.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/ui_controller_template_for_addon.jf @@ -1,67 +1,67 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package #(controllerPackage); - -import com.jfinal.aop.Inject; -import com.jfinal.kit.Ret; -import com.jfinal.plugin.activerecord.Page; - -import io.jboot.web.controller.annotation.RequestMapping; -import io.jboot.web.validate.EmptyValidate; -import #(modelPackage).#(tableMeta.modelName); -import #(modulePackage).service.#(tableMeta.modelName)Service; -import io.jpress.core.menu.annotation.AdminMenu; -import io.jpress.web.base.AdminControllerBase; - - -@RequestMapping(value = "/admin/#(moduleName)/#(tableMeta.name)", viewPath = "/") -public class _#(tableMeta.modelName)Controller extends AdminControllerBase { - - @Inject - private #(tableMeta.modelName)Service service; - - @AdminMenu(text = "#(tableMeta.remarks)管理", groupId = "#(moduleName)") - public void index() { - Page<#(tableMeta.modelName)> entries=service.paginate(getPagePara(), 10); - setAttr("page", entries); - render("views/#(tableMeta.name)_list.html"); - } - - - public void edit() { - int entryId = getParaToInt(0, 0); - #(tableMeta.modelName) entry = entryId > 0 ? service.findById(entryId) : null; - setAttr("#(lowerCaseModelName)", entry); - render("views/#(tableMeta.name)_edit.html"); - } - - public void doSave() { - #(tableMeta.modelName) entry = getModel(#(tableMeta.modelName).class,"#(firstCharToLowerCase(tableMeta.modelName))"); - service.saveOrUpdate(entry); - renderJson(Ret.ok().set("id", entry.getId())); - } - - public void doDel() { - Long id = getIdPara(); - render(service.deleteById(id) ? Ret.ok() : Ret.fail()); - } - - @EmptyValidate(@Form(name = "ids")) - public void doDelByIds() { - service.batchDeleteByIds(getParaSet("ids").toArray()); - renderOkJson(); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package #(controllerPackage); + +import com.jfinal.aop.Inject; +import com.jfinal.kit.Ret; +import com.jfinal.plugin.activerecord.Page; + +import io.jboot.web.controller.annotation.RequestMapping; +import io.jboot.web.validate.EmptyValidate; +import #(modelPackage).#(tableMeta.modelName); +import #(modulePackage).service.#(tableMeta.modelName)Service; +import io.jpress.core.menu.annotation.AdminMenu; +import io.jpress.web.base.AdminControllerBase; + + +@RequestMapping(value = "/admin/#(moduleName)/#(tableMeta.name)", viewPath = "/") +public class _#(tableMeta.modelName)Controller extends AdminControllerBase { + + @Inject + private #(tableMeta.modelName)Service service; + + @AdminMenu(text = "#(tableMeta.remarks)管理", groupId = "#(moduleName)") + public void index() { + Page<#(tableMeta.modelName)> entries=service.paginate(getPagePara(), 10); + setAttr("page", entries); + render("views/#(tableMeta.name)_list.html"); + } + + + public void edit() { + int entryId = getParaToInt(0, 0); + #(tableMeta.modelName) entry = entryId > 0 ? service.findById(entryId) : null; + setAttr("#(lowerCaseModelName)", entry); + render("views/#(tableMeta.name)_edit.html"); + } + + public void doSave() { + #(tableMeta.modelName) entry = getModel(#(tableMeta.modelName).class,"#(firstCharToLowerCase(tableMeta.modelName))"); + service.saveOrUpdate(entry); + renderJson(Ret.ok().set("id", entry.getId())); + } + + public void doDel() { + Long id = getIdPara(); + render(service.deleteById(id) ? Ret.ok() : Ret.fail()); + } + + @EmptyValidate(@Form(name = "ids")) + public void doDelByIds() { + service.batchDeleteByIds(getParaSet("ids").toArray()); + renderOkJson(); + } +} diff --git a/codegen/src/main/java/io/jpress/codegen/templates/ui_edit_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/ui_edit_template.jf index 8cc316baa6ac17c8cf2982fc0d85d90fe7c3c855..3e1025adf262a998a9385daec9088cb500845044 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/ui_edit_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/ui_edit_template.jf @@ -1,97 +1,97 @@ -#[[ -#@layout() -#define css() -#@layout_css?() - -#end -#define script() -#@layout_script?() - - - -#end -]]# - -#('#')define content() -

- -
-

- 编辑/新增 - Edit -

-
- -
- -
-
-
-
-

-
-
- -
- #for(cm : tableMeta.columnMetas) - #set(modelAttrName=firstCharToLowerCase(tableMeta.modelName)+"."+cm.name) - #set(modelAttrName_=firstCharToLowerCase(tableMeta.modelName)+"_"+cm.name) - #if("id"==cm.name) - - #else -
- -
- - #if("java.util.Date"==cm.javaType) - - #elseif("java.lang.Boolean"==cm.javaType) - - - #else - - #end -
-
- #end - #end - -
- - - -
-
-
-
- -
- -
-#('#')end +#[[ +#@layout() +#define css() +#@layout_css?() + +#end +#define script() +#@layout_script?() + + + +#end +]]# + +#('#')define content() +
+ +
+

+ 编辑/新增 + Edit +

+
+ +
+ +
+
+
+
+

+
+
+ +
+ #for(cm : tableMeta.columnMetas) + #set(modelAttrName=firstCharToLowerCase(tableMeta.modelName)+"."+cm.name) + #set(modelAttrName_=firstCharToLowerCase(tableMeta.modelName)+"_"+cm.name) + #if("id"==cm.name) + + #else +
+ +
+ + #if("java.util.Date"==cm.javaType) + + #elseif("java.lang.Boolean"==cm.javaType) + + + #else + + #end +
+
+ #end + #end + +
+ + + +
+
+
+
+ +
+ +
+#('#')end diff --git a/codegen/src/main/java/io/jpress/codegen/templates/ui_list_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/ui_list_template.jf index f118563bdf9e24b47662a75eb665cefdd6e2647d..b82d3293e66981f32dedf14ada5ad32c7b013d3f 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/ui_list_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/ui_list_template.jf @@ -1,106 +1,106 @@ -#('#')@layout() - -#('#')define script() - -#('#')end - -#('#')define content() -
- -
-

- #(tableMeta.remarks)管理 - Items -

-
- -
- -
-
-
-
- -
-
- - 新建 - - -
-
- -
- -
- - - - - - #for(cm : tableMeta.columnMetas) - - #end - - - #('#')for(entry : page.list) - - - - #for(cm : tableMeta.columnMetas) - #if(cm.name=="id") - - #else - - #end - #end - - #('#')end - -
- - #(cm.remarks?? "列名称")
-
- - -
- -
-
- -
-
-#('#')end +#('#')@layout() + +#('#')define script() + +#('#')end + +#('#')define content() +
+ +
+

+ #(tableMeta.remarks)管理 + Items +

+
+ +
+ +
+
+
+
+ +
+
+ + 新建 + + +
+
+ +
+ +
+ + + + + + #for(cm : tableMeta.columnMetas) + + #end + + + #('#')for(entry : page.list) + + + + #for(cm : tableMeta.columnMetas) + #if(cm.name=="id") + + #else + + #end + #end + + #('#')end + +
+ + #(cm.remarks?? "列名称")
+
+ + +
+ +
+
+ +
+
+#('#')end diff --git a/codegen/src/main/java/io/jpress/codegen/templates/ui_listener_template.jf b/codegen/src/main/java/io/jpress/codegen/templates/ui_listener_template.jf index 92a4a80bcf70489b36c28d1bdcb7f40854e18a53..3f1fc6d1eb4f55c678b0fbd59c0bbd9995b5c400 100644 --- a/codegen/src/main/java/io/jpress/codegen/templates/ui_listener_template.jf +++ b/codegen/src/main/java/io/jpress/codegen/templates/ui_listener_template.jf @@ -1,62 +1,62 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

- * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl-3.0.txt - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package #(moduleListenerPakcage); - -import com.jfinal.core.Controller; -import io.jboot.Jboot; -import io.jboot.core.listener.JbootAppListenerBase; -import io.jboot.db.model.Columns; -import io.jpress.core.menu.MenuGroup; -import io.jpress.core.module.ModuleListener; -import java.util.List; - -/** - * @version V1.0 - * @Title: Module 监听器 - * @Description: 每个 module 都应该有这样的一个监听器,用来配置自身Module的信息,比如后台菜单等 - * @Package io.jpress.module.#(moduleName) - */ -public class #(upcasedModuleName)ModuleListener extends JbootAppListenerBase implements ModuleListener { - - - @Override - public String onRenderDashboardBox(Controller controller) { - return null; - } - - @Override - public String onRenderToolsBox(Controller controller) { - return null; - } - - @Override - public void onConfigAdminMenu(List adminMenus) { - MenuGroup menuGroup = new MenuGroup(); - menuGroup.setId("#(moduleName)"); - menuGroup.setText("#(moduleName)"); - menuGroup.setIcon(""); - menuGroup.setOrder(1); - adminMenus.add(menuGroup); - } - - @Override - public void onConfigUcenterMenu(List ucenterMenus) { - - - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

+ * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl-3.0.txt + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package #(moduleListenerPakcage); + +import com.jfinal.core.Controller; +import io.jboot.Jboot; +import io.jboot.core.listener.JbootAppListenerBase; +import io.jboot.db.model.Columns; +import io.jpress.core.menu.MenuGroup; +import io.jpress.core.module.ModuleListener; +import java.util.List; + +/** + * @version V1.0 + * @Title: Module 监听器 + * @Description: 每个 module 都应该有这样的一个监听器,用来配置自身Module的信息,比如后台菜单等 + * @Package io.jpress.module.#(moduleName) + */ +public class #(upcasedModuleName)ModuleListener extends JbootAppListenerBase implements ModuleListener { + + + @Override + public String onRenderDashboardBox(Controller controller) { + return null; + } + + @Override + public String onRenderToolsBox(Controller controller) { + return null; + } + + @Override + public void onConfigAdminMenu(List adminMenus) { + MenuGroup menuGroup = new MenuGroup(); + menuGroup.setId("#(moduleName)"); + menuGroup.setText("#(moduleName)"); + menuGroup.setIcon(""); + menuGroup.setOrder(1); + adminMenus.add(menuGroup); + } + + @Override + public void onConfigUcenterMenu(List ucenterMenus) { + + + } + + +} diff --git a/dbuild.sh b/dbuild.sh index dd0cba3782dab03402856dd19e20fa7803e0d942..ea0fd78dd0cd4e6ccc3eba3fcf5934b515f68589 100755 --- a/dbuild.sh +++ b/dbuild.sh @@ -1,36 +1,36 @@ -#!/bin/bash - -version="$1" - -if [[ "$version" == "" ]]; then - echo "./please designated docker image version" - exit 0 -fi - - -mvn clean install - - -echo "exec : docker build . -t fuhai/jpress:"${version} -docker build . -t fuhai/jpress:${version} - - -echo "exec : docker push fuhai/jpress:"${version} -docker push fuhai/jpress:${version} - - -echo "exec : docker push fuhai/jpress:latest" -docker tag fuhai/jpress:${version} fuhai/jpress:latest -docker push fuhai/jpress:latest - - -echo "exec : docker push jpressio/jpress:"${version} -docker tag fuhai/jpress:latest jpressio/jpress:${version} -docker push jpressio/jpress:${version} - - -echo "exec : docker push jpressio/jpress:latest" -docker tag jpressio/jpress:${version} jpressio/jpress:latest -docker push jpressio/jpress:latest - - +#!/bin/bash + +version="$1" + +if [[ "$version" == "" ]]; then + echo "./please designated docker image version" + exit 0 +fi + + +mvn clean install + + +echo "exec : docker build . -t fuhai/jpress:"${version} +docker build . -t fuhai/jpress:${version} + + +echo "exec : docker push fuhai/jpress:"${version} +docker push fuhai/jpress:${version} + + +echo "exec : docker push fuhai/jpress:latest" +docker tag fuhai/jpress:${version} fuhai/jpress:latest +docker push fuhai/jpress:latest + + +echo "exec : docker push jpressio/jpress:"${version} +docker tag fuhai/jpress:latest jpressio/jpress:${version} +docker push jpressio/jpress:${version} + + +echo "exec : docker push jpressio/jpress:latest" +docker tag jpressio/jpress:${version} jpressio/jpress:latest +docker push jpressio/jpress:latest + + diff --git a/doc/about_jpress.md b/doc/about_jpress.md index 0f03236760fce99d126c336d0d2ac5f3f46148f6..801f5d51225b8cf7df07f72e5a75a98197ad7482 100644 --- a/doc/about_jpress.md +++ b/doc/about_jpress.md @@ -1,17 +1,17 @@ -# 关于JPress - -### 1.JPress公众号 - -![](./images/jpress_qrcode.jpg) - - - -### 2.关于JPress的相关文章 - -- [JPress模板开发视频教程.mp4](https://mp.weixin.qq.com/s/DZ0RQtpeVocdzs_h1bW9GA) -- [JPress 2019 新计划](https://mp.weixin.qq.com/s/OvEkHa9pL6vRnMLZNJ_0zg) -- [历时2年,JPress v1.0 正式版虽然发布了,但是作者想说的是...](https://mp.weixin.qq.com/s/raxE6tnR8gDYNjFMcFTBLg) -- [JPress 荣获 GVP,发布全新的精品主题祝贺](https://mp.weixin.qq.com/s/r6J5JvlG16WEe7PCuoxjZg) -- [JPress School 发布了](https://mp.weixin.qq.com/s/GbNv0xaK6jruWqTDJ_Ospw) -- [JPress开发路线图出炉,发力对接微信小程序...](https://mp.weixin.qq.com/s/n8xdzDPKacXHYVXfOLMhLQ) +# 关于JPress + +### 1.JPress公众号 + +![](./images/jpress_qrcode.jpg) + + + +### 2.关于JPress的相关文章 + +- [JPress模板开发视频教程.mp4](https://mp.weixin.qq.com/s/DZ0RQtpeVocdzs_h1bW9GA) +- [JPress 2019 新计划](https://mp.weixin.qq.com/s/OvEkHa9pL6vRnMLZNJ_0zg) +- [历时2年,JPress v1.0 正式版虽然发布了,但是作者想说的是...](https://mp.weixin.qq.com/s/raxE6tnR8gDYNjFMcFTBLg) +- [JPress 荣获 GVP,发布全新的精品主题祝贺](https://mp.weixin.qq.com/s/r6J5JvlG16WEe7PCuoxjZg) +- [JPress School 发布了](https://mp.weixin.qq.com/s/GbNv0xaK6jruWqTDJ_Ospw) +- [JPress开发路线图出炉,发力对接微信小程序...](https://mp.weixin.qq.com/s/n8xdzDPKacXHYVXfOLMhLQ) - [JPress 1.0 发布了](https://mp.weixin.qq.com/s/N_bJIEz_Y52l--qj7f2sSg) \ No newline at end of file diff --git a/doc/addon_dev.md b/doc/addon_dev.md index 3ed9f00f3fbb092a2b25f9f76875830777222152..04bce490e6d6fb8cd12629bfdc4a738cfb47b925 100644 --- a/doc/addon_dev.md +++ b/doc/addon_dev.md @@ -1,60 +1,60 @@ -# 插件开发 - -开发插件,和开发一个 Maven Module 没有什么区别,需要注意的是 JPress 插件有自己独立的配置文件。 - -## 插件的相关文件 - -- addon.txt :插件的声明文件 -- config.txt : 插件的配置文件 - -## addon.txt - -``` -id=io.jpress.addon.helloworld -title=hello world -description=这只是一个插件demo,方便开发者参考开发 -author=海哥 -authorWebsite= -version= -versionCode=1 -``` - -- id:插件的唯一ID,在整个 JPress 应用中,不允许两个ID一样的插件同时存在。 -- title: 插件的名称,这个名称会在后台的插件列表里显示 -- description:插件的描述 -- author:插件的作者 -- authorWebsite:插件作者的官网,或者插件的官网 -- version:插件的版本号,可以是字符串,例如: v1.0.0 -- versionCode:插件的版本号码,必须是数字类型,以后插件的升级检测会通过 versionCode 进行验证,而非 version - -## config.txt - -``` -db.type = mysql -db.url -db.user -db.password -db.driverClassName = "com.mysql.jdbc.Driver" -db.connectionInitSql -db.poolName -db.cachePrepStmts = true -db.prepStmtCacheSize = 500 -db.prepStmtCacheSqlLimit = 2048 -db.maximumPoolSize = 10 -db.maxLifetime -db.idleTimeout -db.minimumIdle = 0 -db.sqlTemplatePath -db.sqlTemplate -db.factory -db.shardingConfigYaml -db.dbProFactory -db.containerFactory -db.transactionLevel -db.table #此数据源包含哪些表,这个配置会覆盖@Table注解的配置 -db.exTable #该数据源排除哪些表,这个配置会修改掉@Table上的配置 -db.dialectClass -db.activeRecordPluginClass -``` - - +# 插件开发 + +开发插件,和开发一个 Maven Module 没有什么区别,需要注意的是 JPress 插件有自己独立的配置文件。 + +## 插件的相关文件 + +- addon.txt :插件的声明文件 +- config.txt : 插件的配置文件 + +## addon.txt + +``` +id=io.jpress.addon.helloworld +title=hello world +description=这只是一个插件demo,方便开发者参考开发 +author=海哥 +authorWebsite= +version= +versionCode=1 +``` + +- id:插件的唯一ID,在整个 JPress 应用中,不允许两个ID一样的插件同时存在。 +- title: 插件的名称,这个名称会在后台的插件列表里显示 +- description:插件的描述 +- author:插件的作者 +- authorWebsite:插件作者的官网,或者插件的官网 +- version:插件的版本号,可以是字符串,例如: v1.0.0 +- versionCode:插件的版本号码,必须是数字类型,以后插件的升级检测会通过 versionCode 进行验证,而非 version + +## config.txt + +``` +db.type = mysql +db.url +db.user +db.password +db.driverClassName = "com.mysql.jdbc.Driver" +db.connectionInitSql +db.poolName +db.cachePrepStmts = true +db.prepStmtCacheSize = 500 +db.prepStmtCacheSqlLimit = 2048 +db.maximumPoolSize = 10 +db.maxLifetime +db.idleTimeout +db.minimumIdle = 0 +db.sqlTemplatePath +db.sqlTemplate +db.factory +db.shardingConfigYaml +db.dbProFactory +db.containerFactory +db.transactionLevel +db.table #此数据源包含哪些表,这个配置会覆盖@Table注解的配置 +db.exTable #该数据源排除哪些表,这个配置会修改掉@Table上的配置 +db.dialectClass +db.activeRecordPluginClass +``` + + diff --git a/doc/install.md b/doc/install.md index 1e719a2a57b49ca68e3b056471f9ca8396a3731c..88687fe63a3c3b6938eb80663a988d596c531d0c 100644 --- a/doc/install.md +++ b/doc/install.md @@ -1,169 +1,169 @@ -# JPress 安装 - -## 目录 -- 下载 JPress -- 通过 Docker 进行安装 -- 通过 宝塔 进行安装 -- 手动进行安装 -- 安装过程注意事项 -- JPress的配置简介 -- 常见问题 - -## 下载JPress - -- 下载源码 -- 下载tomcat压缩包 -- 下载运行包 - -**注意:** 若您通过 Docker 运行JPress,则无需下载,通过 Docker 的相关命令可以直接安装,详细请查看《通过 Docker 进行安装》章节。 - -#### 下载源码 - -通过git命令下载 - -``` -git clone https://gitee.com/fuhai/jpress.git -``` -下载完成后,你需要通过 maven 进行编译才能使用,maven编译命令: - -``` -mvn clean install -``` - -执行该命令,稍等片刻,待命令执行完毕后,会在 `starter/target` 目录下生成一个 `starter-2.0` 的文件夹和 `starter-2.0.zip` 的压缩包,通过执行 `starter-2.0` 里的 `jpress.sh` 可以直接运行 JPress。 - -倘若在执行maven编译的过程中出错,请对maven进行如下配置: - - * maven版本建议用3.0 以上,2.x没有测试过 - * java版本1.8 - * maven注意添加aliyun的源,修改 `maven/conf/setting.xml`文件,找到 mirrors 节点 ,修改如下: - - ```xml - - - alimaven - aliyun maven - http://maven.aliyun.com/nexus/content/groups/public/ - central - - - - ``` - -#### 下载tomcat压缩包 -进入 Gitee 的 JPress 发行页面进行下载 - ->链接地址: https://gitee.com/fuhai/jpress/releases - -在每个版本的发行下方,会有对应版本的下载链接,点击即可下载,如下图所示: -![](./images/install_01.jpg) - - - -## 通过 Docker 安装 JPress - -通过 Docker 进行安装 JPress , 需要提前在本地安装好 Docker。 - -#### Docker 的安装 - - -* [Mac](https://docs.docker.com/docker-for-mac/install) -* [Windows](https://docs.docker.com/docker-for-windows/install) -* [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu) -* [Debian](https://docs.docker.com/install/linux/docker-ce/debian) -* [CentOS](https://docs.docker.com/install/linux/docker-ce/centos) -* [Fedora](https://docs.docker.com/install/linux/docker-ce/fedora) -* [其他 Linux 发行版](https://docs.docker.com/install/linux/docker-ce/binaries) - -通过以上链接,下载 docker 并安装完毕后,就可以开始安装 JPress 了。 - -#### 在 Linux 上安装 JPress : - -``` -wget https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml -docker-compose up -d -``` - -#### 在 Mac OS(苹果电脑)上安装 JPress : - -``` -curl -O https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml -docker-compose up -d -``` - -执行完毕以上命令之后,访问 `http://127.0.0.1:8080` 即可。 - - -## 通过 宝塔 进行安装 JPress - -宝塔是一个优秀的可视化服务器管理工具,提供了web操作面板,方便我们通过宝塔的web面板对服务器进行管理,例如 - -1、数据库安装、账号密码管理和数据管理 -2、FTP账号的管理 -3、各种服务器软件的安装,php、tomcat、nginx等 -4、文件管理 - -宝塔的官网网站: http://wwww.bt.cn - -通过宝塔进行安装 JPress,大概分为以下几个步骤: - -1、购买服务器并安装宝塔 -2、通过宝塔的后台面板安装nginx、Mysql和tomcat。 -3、创建网站,并启用tomcat功能 -4、上传JPress的war包,并解压缩 -5、访问网站,走jpress自动安装过程 - -#### 1、购买服务器并安装宝塔 -购买服务器建议购买阿里云的 centos 7.4 以上 ,里面不要安装其他任何功能(笔者在centos 7.2 下安装宝塔,nginx是无法使用的,centos 7.4 没问题) - -安装宝塔非常简单,用 root 账号进入Linux服务,然后执行如下命令即可自动安装宝塔: - -``` -yum install -y wget && wget -O install.sh http:// -download.bt.cn/install/install_6.0.sh && bash install.sh -``` - -需要注意的是:安装的过程中控制台会打印安装的过程,在安装完成后,控制台会输出宝塔的登陆地址、账号和密码。 - -重要事情说三遍: - ->登陆地址、账号和密码,这部分务必要记住。 ->登陆地址、账号和密码,这部分务必要记住。 ->登陆地址、账号和密码,这部分务必要记住。 - - -#### 2、通过宝塔的后台,安装nginx、mysql和tomcat - -可以在宝塔的后台,通过 `软件管理 > 运行环境` 可以找到 nginx、mysql 和 tomcat。 - -点击安装即可。 - -需要注意的是各个软件的版本号: - -* nginx : 1.14 -* tomcat : 8.5 -* mysql : 5.6 - -#### 3、创建网站 - -在宝塔后台,通 `网站 > 添加网站` 创建一个新的网站。 - -创建网站的时候需要注意的是,创建mysql数据库的时候,版本要选择 `utf8mb4` 编码。 - -在宝塔后台的 `网站` 里,点击网站域名,在 `tomcat` 菜单里,启用 tomcat 功能。 -![](./images/install_02.jpg) - -#### 4、上传war,并解压缩 - -在宝塔后台的 `网站` 里,点击根目录对应的目录链接,然后上传 jpress.war 到此目录。 - - -因为宝塔无法对 .war 这种文件格式解压缩,所以需要重命名为 jpress.zip ,当然也可以在本地先把 jpress.war 先重命名为 jpress.zip 然后再上传也可以。 - -操作完成后,点击 jpress.zip 的解压缩即可。 - -#### 5、访问网站走jpress自动安装过程 - -访问你的域名,JPress自动引导进行安装,在JPress安装向导的过程中,只需要填写宝塔创建完毕的数据库账号和密码即可。 - -## 手动进行安装 +# JPress 安装 + +## 目录 +- 下载 JPress +- 通过 Docker 进行安装 +- 通过 宝塔 进行安装 +- 手动进行安装 +- 安装过程注意事项 +- JPress的配置简介 +- 常见问题 + +## 下载JPress + +- 下载源码 +- 下载tomcat压缩包 +- 下载运行包 + +**注意:** 若您通过 Docker 运行JPress,则无需下载,通过 Docker 的相关命令可以直接安装,详细请查看《通过 Docker 进行安装》章节。 + +#### 下载源码 + +通过git命令下载 + +``` +git clone https://gitee.com/fuhai/jpress.git +``` +下载完成后,你需要通过 maven 进行编译才能使用,maven编译命令: + +``` +mvn clean install +``` + +执行该命令,稍等片刻,待命令执行完毕后,会在 `starter/target` 目录下生成一个 `starter-2.0` 的文件夹和 `starter-2.0.zip` 的压缩包,通过执行 `starter-2.0` 里的 `jpress.sh` 可以直接运行 JPress。 + +倘若在执行maven编译的过程中出错,请对maven进行如下配置: + + * maven版本建议用3.0 以上,2.x没有测试过 + * java版本1.8 + * maven注意添加aliyun的源,修改 `maven/conf/setting.xml`文件,找到 mirrors 节点 ,修改如下: + + ```xml + + + alimaven + aliyun maven + http://maven.aliyun.com/nexus/content/groups/public/ + central + + + + ``` + +#### 下载tomcat压缩包 +进入 Gitee 的 JPress 发行页面进行下载 + +>链接地址: https://gitee.com/fuhai/jpress/releases + +在每个版本的发行下方,会有对应版本的下载链接,点击即可下载,如下图所示: +![](./images/install_01.jpg) + + + +## 通过 Docker 安装 JPress + +通过 Docker 进行安装 JPress , 需要提前在本地安装好 Docker。 + +#### Docker 的安装 + + +* [Mac](https://docs.docker.com/docker-for-mac/install) +* [Windows](https://docs.docker.com/docker-for-windows/install) +* [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu) +* [Debian](https://docs.docker.com/install/linux/docker-ce/debian) +* [CentOS](https://docs.docker.com/install/linux/docker-ce/centos) +* [Fedora](https://docs.docker.com/install/linux/docker-ce/fedora) +* [其他 Linux 发行版](https://docs.docker.com/install/linux/docker-ce/binaries) + +通过以上链接,下载 docker 并安装完毕后,就可以开始安装 JPress 了。 + +#### 在 Linux 上安装 JPress : + +``` +wget https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml +docker-compose up -d +``` + +#### 在 Mac OS(苹果电脑)上安装 JPress : + +``` +curl -O https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml +docker-compose up -d +``` + +执行完毕以上命令之后,访问 `http://127.0.0.1:8080` 即可。 + + +## 通过 宝塔 进行安装 JPress + +宝塔是一个优秀的可视化服务器管理工具,提供了web操作面板,方便我们通过宝塔的web面板对服务器进行管理,例如 + +1、数据库安装、账号密码管理和数据管理 +2、FTP账号的管理 +3、各种服务器软件的安装,php、tomcat、nginx等 +4、文件管理 + +宝塔的官网网站: http://wwww.bt.cn + +通过宝塔进行安装 JPress,大概分为以下几个步骤: + +1、购买服务器并安装宝塔 +2、通过宝塔的后台面板安装nginx、Mysql和tomcat。 +3、创建网站,并启用tomcat功能 +4、上传JPress的war包,并解压缩 +5、访问网站,走jpress自动安装过程 + +#### 1、购买服务器并安装宝塔 +购买服务器建议购买阿里云的 centos 7.4 以上 ,里面不要安装其他任何功能(笔者在centos 7.2 下安装宝塔,nginx是无法使用的,centos 7.4 没问题) + +安装宝塔非常简单,用 root 账号进入Linux服务,然后执行如下命令即可自动安装宝塔: + +``` +yum install -y wget && wget -O install.sh http:// +download.bt.cn/install/install_6.0.sh && bash install.sh +``` + +需要注意的是:安装的过程中控制台会打印安装的过程,在安装完成后,控制台会输出宝塔的登陆地址、账号和密码。 + +重要事情说三遍: + +>登陆地址、账号和密码,这部分务必要记住。 +>登陆地址、账号和密码,这部分务必要记住。 +>登陆地址、账号和密码,这部分务必要记住。 + + +#### 2、通过宝塔的后台,安装nginx、mysql和tomcat + +可以在宝塔的后台,通过 `软件管理 > 运行环境` 可以找到 nginx、mysql 和 tomcat。 + +点击安装即可。 + +需要注意的是各个软件的版本号: + +* nginx : 1.14 +* tomcat : 8.5 +* mysql : 5.6 + +#### 3、创建网站 + +在宝塔后台,通 `网站 > 添加网站` 创建一个新的网站。 + +创建网站的时候需要注意的是,创建mysql数据库的时候,版本要选择 `utf8mb4` 编码。 + +在宝塔后台的 `网站` 里,点击网站域名,在 `tomcat` 菜单里,启用 tomcat 功能。 +![](./images/install_02.jpg) + +#### 4、上传war,并解压缩 + +在宝塔后台的 `网站` 里,点击根目录对应的目录链接,然后上传 jpress.war 到此目录。 + + +因为宝塔无法对 .war 这种文件格式解压缩,所以需要重命名为 jpress.zip ,当然也可以在本地先把 jpress.war 先重命名为 jpress.zip 然后再上传也可以。 + +操作完成后,点击 jpress.zip 的解压缩即可。 + +#### 5、访问网站走jpress自动安装过程 + +访问你的域名,JPress自动引导进行安装,在JPress安装向导的过程中,只需要填写宝塔创建完毕的数据库账号和密码即可。 + +## 手动进行安装 diff --git a/doc/quick_start.md b/doc/quick_start.md index 2be79f17113f977265805e0cd124df2d86e1c10a..7ec1f2e555e4352567317165d9bdff26cada99a7 100644 --- a/doc/quick_start.md +++ b/doc/quick_start.md @@ -1,56 +1,56 @@ -# 快速开始 - -## 目录 - -- 准备 -- 下载 -- 编译 -- 运行 -- 停止 -- 重启 - -## 准备 - -- 安装 Java 环境 -- 安装 maven 编译环境 - -**安装Java环境** - -进入网址 https://www.java.com ,通过网站引导即可进行安装。 - - -**安装 maven 编译环境** - -参考 Maven 官方文档:http://maven.apache.org/ - -## 下载 - -``` -git clone https://gitee.com/fuhai/jpress.git -``` - -## 编译 - -``` -cd jpress -mvn clean install -``` - -## 运行 - -``` -cd starter/target/starter-2.0 -./jpress.sh start -``` - -## 停止 - -``` -./jpress stop -``` - -## 重启 - -``` -./jpress restart +# 快速开始 + +## 目录 + +- 准备 +- 下载 +- 编译 +- 运行 +- 停止 +- 重启 + +## 准备 + +- 安装 Java 环境 +- 安装 maven 编译环境 + +**安装Java环境** + +进入网址 https://www.java.com ,通过网站引导即可进行安装。 + + +**安装 maven 编译环境** + +参考 Maven 官方文档:http://maven.apache.org/ + +## 下载 + +``` +git clone https://gitee.com/fuhai/jpress.git +``` + +## 编译 + +``` +cd jpress +mvn clean install +``` + +## 运行 + +``` +cd starter/target/starter-2.0 +./jpress.sh start +``` + +## 停止 + +``` +./jpress stop +``` + +## 重启 + +``` +./jpress restart ``` \ No newline at end of file diff --git a/doc/readme.md b/doc/readme.md index 4c8c25e9717af0b9f03506d8d50f935a704c1166..582acf841543bcacce141213e6eb346d205e0af7 100644 --- a/doc/readme.md +++ b/doc/readme.md @@ -1,1196 +1,1196 @@ -# JPress 文档 - - - -在使用JPress之前,你应该对数据库、服务器等有基本的认识。本文档是建立在这些基础知识之上的。 - -另外可以通过以下几种方式获得帮助: - -1. JPress官方公众号:jpressio -2. JPress交流QQ群:288397536 -3. 开源中国进行发帖提问。 - -## JPress安装 - -### 通过Docker进行安装 - -Linux : - -``` -wget https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml -docker-compose up -d -``` - -Mac OS : - -``` -curl -O https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml -docker-compose up -d -``` - -执行完毕以上命令之后,访问 `http://127.0.0.1:8080` 即可。 - -### 手动安装 - -JPress手动安装需要以下几个步骤: - -1. 下载JPress源码 -2. 通过maven编译JPress成war包(或可执行程序) -3. 启动JPress - -#### 1.下载JPress源码 - -下载JPress源码通过以下几种方式: - -1、git clone - -``` -git clone https://gitee.com/fuhai/jpress.git -``` - -2、进入 Gitee 的 JPress 发行页面进行下载 - -链接地址: https://gitee.com/fuhai/jpress/releases - -#### 2.通过Maven编译JPress成war包和可执行程序 - -JPress可以编译成war包和可执行程序,war需要在tomcat等web容器下运行。可执行程序内置undertow,不需要其他第三方web容器,运行脚本即可通过浏览器访问jpress应用。 - - -下载好 JPress 源码后,通过 shell 进入源码目录,执行如下 maven 命令: - -```shell -mvn package -``` - -稍等片刻,待命令执行完毕之后,即可在 `starter-tomcat/target` 目录下生成 `starter-tomcat-2.0.war` 的war包,在 `starter/target/` 目录下生成 starter-2.0 的文件夹,starter-2.0 文件夹的目录如下: - -``` -├── config -├── lib -├── webapp -├── jpress.sh -└── jpress.bat -``` - - 若编译不通过注意事项: - - * maven版本建议用3.0 以上,2.x没有测试过 - * java版本1.8 - * maven注意添加aliyun的源,修改 `maven/conf/setting.xml`文件,找到 mirrors 节点 ,修改如下: - - ```xml - - - alimaven - aliyun maven - http://maven.aliyun.com/nexus/content/groups/public/ - central - - - - ``` - - -#### 3、启动JPress - -##### 启动 jpress war 包 - -拷贝`starter-tomcat/target` 目录下的 `starter-tomcat-1.0.war` war包,放到tomcat的webapp目录下,手动解压缩。 - -启动tomcat(运行 `tomcat/bin/startup.sh`),浏览器输入 `http://127.0.0.1:8080/starter-tomcat-2.0` 即可访问。 - -若把 `tomcat/webapp/starter-tomcat-2.0` 里面的文件拷贝到 `tomcat/webapp/ROOT`,访问`http://127.0.0.1:8080`即可。 - - -##### 启动 jpress 可执行程序 - - -拷贝`starter/target/` 的 `starter-2.0` 目录,放到 Linux 上。 - - -执行 `./jpress.sh start` 脚本也可以启动jpress项目(window系统下执行 `./jpress.bat`)。 - - - -## 模板制作 - -JPress模板主要是由html、css、js和JPress标签组成,JPress标签的主要作用是用于读取后台数据,逻辑控制。 - -与此同时、JPress模板文件的文件名也是固定的,目录结构如下: - - -|模板文件| 描述 | 备注 | -| --- | --- | --- | -| index.html |首页模板| | -| error.html |错误页面模板| 当系统发生错误的时候,会自动调用此页面进行渲染,也可以扩展为 error_404.html,当发生404错误的时候优先使用此文件,同理可以扩展 error_500.html ,当系统发生500错误的时候调用此文件渲染。 | -| setting.html |后台的模板设置页面| 当次html不存在的时候,用户进入后台的模板设置,会显示此模板不支持设置功能 | -| screenshot.png |模板缩略图| 用于在后台的模板列表里显示的图片 | -| template.properties |模板信息描述文件| 文件格式在下方 | -| page.html |页面模块的模板| page.html 可以扩展为 page_aaa.html 、page_bbbb.html ,当模板扩展出 page_xxx.html 的时候,用户在后台发布页面内容的时候,就可以选择使用哪个模板样式进行渲染。例如: page_xxx.html 其中 `xxx` 为样式的名称。| -| article.html | 文章详情模板| 和page模块一样,article.html 可以扩展出 article_styel1.html、article_style2.html,这样,用户在后台发布文章的时候,可以选择文章样式。(备注:用户中心投稿不能选择样式) | -| artlist.html | 文章列表模板| 和page、article一样,可以通过样式 | -| artsearch.html | 文章搜索模板| 和page、article一样,可以通过样式 | -| user_login.html | 用户登录页面| JPress已经内置了登录页面,但是,当模板下有 user_login.html 的时候,就会自动使用模板下的这个页面来渲染 | -| user_register.html | 用注册页面| 用法通 user_login.html | - - -备注:所有的模板文件都可以扩展出专门用于渲染手机浏览器的模板。 - -例如:首页的渲染模板是 `index.html` ,如果当前目录下有 `index_h5.html`,那么,当用户通过手机访问网站的时候,JPress 会自动使用 `index_h5.html` 去渲染。 page 和 article、artlist 同理。 - -template.properties 文件配置如下 - -``` -id = cn.jeanstudio.bluelight -title = BlueLight -description = BlueLight是JeanStudio工作室为JPress设计的官网模板 -anthor = jeanStudio -authorWebsite = http://www.jeanstudio.cn -version = 1.0 -versionCode = 1 -updateUrl = -screenshot = screenshot.png -``` - -* id :模板ID,全网唯一,建议用域名+名称的命名方式 -* title :模板名称 -* description :模板简介 -* anthor :模板作者 -* authorWebsite :模板作者的官网 -* version :版本(不添加默认为1.0.0) -* versionCode :版本号(只能是数字,不填写默认为1) -* updateUrl :此模板升级的url地址 -* screenshot :此模板的缩略图图片(不填写默认为:screenshot.png) - - - - -#### 模板标签 - -有了以上这些目录结构,实际上不用任何的标签就可以成为一套模板了,只是这个模板是静态模板,不能读取后台数据。 - -只有通过在静态的html上,添加 JPress 标签,才能可以读取后台数据。 - -目前,JPress内置的模板标签如下: - -**1、全局标签,全局标签用全用大写显示,全局标签在任意模板页面都可以使用。** - -| 标签名称 | 数据类型 | 标签描述 | -| --- | --- | --- | -| #(WEB_NAME ??) | 字符串 | 网站名称 | -| #(WEB_TITLE ??) | 字符串 | 网站标题 | -| #(WEB_SUBTITLE ??) | 字符串 | 网站副标题 | -| #(WEB_DOMAIN ??) | 字符串 | 网站域名 | -| #(WEB_COPYRIGHT ??) | 字符串 | 网站版权信息 | -| #(SEO_TITLE ??) | 字符串 | 网站SEO标题 | -| #(SEO_KEYWORDS ??) | 字符串 | 网站SEO关键字 | -| #(SEO_DESCRIPTION ??) | 字符串 | 网站SEO描述 | -| MENUS | 数据列表( list ) | 菜单数据 | - -标签描述,标签建议用 `#( 名称 ??)` 的方式来读取数据,而不是用 `#(名称)` 两个问号(??)的意思是如果 后台填写的名称为空格,那么就用 两个问号(??)之后的内容来显示。 - -例如: -`#(WEB_NAME ??)` 表示优先使用 WEB_NAME 来显示,但是当 WEB_NAME 为空的时候,显示空数据(因为两个问好(??)之后的内容为空)。 - -`#(WEB_NAME ?? WEB_TITLE)` 表示优先使用 WEB_NAME 来显示,但是当 WEB_NAME 为空的时候,用 WEB_TITLE(网站标题) 来显示。 - -`#(SEO_TITLE ?? WEB_TITLE +'-'+ WEB_SUBTITLE)` 表示优先使用 SEO_TITLE(SEO标题) 来显示,但是当 SEO_TITLE 为空的时候,用 `WEB_TITLE - WEB_SUBTITLE` 来显示。 - -有了以上知识后,我们的 index.html 首页模板文件可以如下: - -```html - - - - #(SEO_TITLE ?? (WEB_TITLE + '-' + WEB_SUBTITLE)) - - - - -这是首页.... - - -``` - -以上内容都只是针对 `字符串` 这种数据类型进行展示的,全局标签中还有一种数据类型叫 `数据列表( list )`,那么,怎么来显示数据列表呢? - -这个时候`#( 名称 ??)`就不能正常显示了,需要用到一个新的标签: - -```html -#for -... -#end -``` - -`#for ... #end` 标签也叫循环标签,意思是把列表循环显示出来。 - -对于 `MENUS` 这种数据类型为 `数据列表( list )` 的数据,`#for ... #end` 标签使用如下。 - - -```html -#for(menu : MENUS) -

  • #(menu.text ??)
  • -#end -``` - -这样,若我们在后台创建了5个菜单,那么html会输出 5个 `
  • ...
  • ` - -对于以上的菜单显示,还有一个问题就是如何显示二级菜单呢? - -代码如下: - -```html -#for(menu : MENUS) -
  • #(menu.text ??)
  • - #if(menu.hasChild()) -
    - #for(childMenu : menu.getChilds()) -
  • #(menu.text ??)
  • - #end -
    - #end -#end -``` - -以上代码显示了所有菜单的的二级菜单,但是,有些时候我们想在网站的某些位置,显示 **当前菜单** 下的子菜单,如何做呢? - - -代码如下: - -```html -#for(me: MENUS) - #if(me.isActive && me.hasChild()) - - - #end -#end -``` - - - -**2、数据指令,数据指令一般情况下只能用于特有页面** - -文章相关指令: - -| 指令名称 | 可用页面 |描述 | -| --- | --- | --- | -| #article() | 任意 | 用于读取特定的单篇文章 | -| #articles() | 任意 | 用于读取文章列表,例如:热门文章文章、最新评论文章列表等等 | -| #tagArticles() | 任意 | 读取某个tag下的文章列表 | -| #categoryArticles() | 任意 | 读取某个分类下的文章列表 | -| #articlePage() | 任意 | 用于对文章列表进行的内容和分页进行显示 | -| #commentPage() | 文章详情:article.html | 用于对文章评论的内容和分页进行显示 | -| #nextArticle() | 文章详情:article.html | 下一篇文章 | -| #previousArticle() | 文章详情:article.html | 上一篇文章 | -| #relevantArticles() | 文章详情:article.html | 相关文章列表,相同标签的的文章 | -| #categories() | 任意 | 读取文章模块的所有分类 | -| #tags() | 任意 | 用于读取文章标签 | -| #articleCategories() | 任意 | 用于读取某一篇文章的所属分类,例如:文章的标签、文章的分类等 | -| #articleSearchPage() | 文章搜索结果页 artsearch.html | 用于渲染搜索结果 | - - -产品相关指令: - -| 指令名称 | 可用页面 |描述 | -| --- | --- | --- | -| #products() | 任意 | 获取产品的列表 | -| #categoryProducts() | 任意 | 用根据分类获取产品内容 | -| #nextProduct() | 产品详情:product.htm | 下一个产品 | -| #previousProduct() | 产品详情:product.htm| 上一个产品 | -| #productCategories() | 任意 | 获取某个产品对应的分类或者标签 | -| #productCategoryList() | 任意 | 产品分类列表 | -| #productCommentPage() | 产品详情:product.htm | 产品评论分页 | -| #product() | 任意 | 根据产品id或者slug读取产品信息 | -| #productPage() | 任意 | 产品分页 | -| #productSearchPage() | 任意 | 产品搜索分页 | -| #productTags() | 任意 | 产品标签 | -| #relevantProducts() | 任意 | 某个产品的相关产品(相同tag的产品) | - - - -页面相关指令: - -| 指令名称 | 可用页面 |描述 | -| --- | --- | --- | -| #page() | 任意 | 用于读取某个页面 | -| #pages() | 任意 | 用于读取页面列表 | - - - 用户相关指令: - -| 指令名称 | 可用页面 |描述 | -| --- | --- | --- | -| #users() | 暂不支持 | 用于读取页面列表 | - - -##### #article() 指令的用法 - -此指令是用来读取一篇文章,网站的任意页面进行展示。 - -```html -#article() -#(article.title) -
    #(article.content)
    -#end -``` - -##### #articles() 指令的用法 - -此指令是在任何页面,用来读取文章列表。例如:最新文章、热门文章等 - -```html -#articles(flag="",hasThumbnail="",orderBy="",count=10) - #for(article : articles) - #(article.title) - #end -#end -``` - -**#articles() 指令支持的参数有:** - -* flag:文章标识,这个是在编辑文章的时候自由填写。 -* hasThumbnail:是否需要缩略图,值为 true 和 false。 -* orderBy :根据什么进行排序,目前支持的值有:order_number(用户自定义排序)、comment_count(文章的评论数量)、comment_time(文章的评论时间)、view_count(文章的访问量)、created(文章的创建时间)、modified(文章的修改时间) -* count :要显示多少篇文章 -* style :文章样式 - -##### #tagArticles() 指令的用法 - -此指令是在任何页面,用来读取文章列表。例如:最新文章、热门文章等 - -```html -#tagArticles(tag="aaa",hasThumbnail="",orderBy="",count=10) - #for(article : articles) - #(article.title) - #end -#end -``` - -**#tagArticles() 指令支持的参数有:** - -* tag:哪个tag。 -* hasThumbnail:是否需要缩略图,值为 true 和 false。 -* orderBy :根据什么进行排序,目前支持的值有:order_number(用户自定义排序)、comment_count(文章的评论数量)、comment_time(文章的评论时间)、view_count(文章的访问量)、created(文章的创建时间)、modified(文章的修改时间) -* count :要显示多少篇文章 - -##### #categoryArticles() 指令的用法 - -此指令是在任何页面,用来读取文章列表。例如:最新文章、热门文章等 - -```html -#categoryArticles(categoryFlag="",hasThumbnail="",orderBy="",count="") - #for(article : articles) - #(article.title) - #end -#end -``` - -**#categoryArticles() 指令支持的参数有:** - -* categoryFlag:分类的标识。 -* hasThumbnail:是否需要缩略图,值为 true 和 false。 -* orderBy :根据什么进行排序,目前支持的值有:order_number(用户自定义排序)、comment_count(文章的评论数量)、comment_time(文章的评论时间)、view_count(文章的访问量)、created(文章的创建时间)、modified(文章的修改时间) -* count :要显示多少篇文章 - -##### #articlePage() 指令的用法 -指令 #articlePage() 只能用在文章列表页,也就是 artlist.html 模板文件及其扩展文件。 - -```java -#articlePage() - - #for(article : articlePage.list) - - 文章标题是:#(article.title ??) - -
    - 文章内容是:#maxLength(article.text,100) -
    - #end - - #articlePaginate() - #for(page : pages) - - #(page.text ??) - - #end - #end - -#end -``` -**说明** -指令 #articlePage() 内部又包含了另一个指令 #articlePaginate(),#articlePaginate()是用于显示上一页和下一下。 - -**指令 #articlePage() 的参数有:** - -* pageSize :可以用来指定当前页面有多少条数据,默认值是:10。也就是说 `#articlePage()` 等同于 `#articlePage(pageSize=10)` - -**分页指令#articlePaginate()的参数有** - -* previousClass :上一页的样式,默认值:previous -* nextClass :下一页的样式,默认值:next -* activeClass :当前页面的样式,默认值:active -* disabledClass :禁用的样式(当下一页没有数据的时候,会使用此样式),默认值:disabled -* anchor :锚点链接 -* onlyShowPreviousAndNext :是否只显示上一页和下一页(默认值为false,一般情况下在手机端才会把这个值设置true) -* previousText :上一页按钮的文本内容,默认值:上一页 -* nextText :下一页按钮的文本内容,默认值:下一页 -* firstGotoIndex : 是否让第一页进入首页,默认值:false - -##### #commentPage()指令的用法 - -指令 #commentPage() 只能用在文章详情页,也就是 article.html 模板文件及其扩展文件。用于读取这篇文章的相关评论信息以及评论的分页功能。 - -```html -#commentPage() - - #for(comment : commentPage.list) -
    评论内容是:#(comment.content ??)
    -
    评论作者是:#(comment.authro ??)
    - #end - - #commentPaginate() - #for(page : pages) - - #(page.text ??) - - #end - #end - -#end -``` -**说明** -和一样#articlePage(),#commentPage()指令 内部又包含了另一个指令 #commentPaginate(),#commentPaginate()是用于显示评论的上一页和下一下。 - -**指令 #commentPage() 的参数有:** - -* pageSize :可以用来指定当前文章详情,每页的评论条数是多少,默认值是:10。也就是说 `#commentPage()` 等同于 `#commentPage(pageSize=10)` - -**分页指令#commentPaginate()的参数有** - -* previousClass :上一页的样式,默认值:previous -* nextClass :下一页的样式,默认值:next -* activeClass :当前页面的样式,默认值:active -* disabledClass :禁用的样式(当下一页没有数据的时候,会使用此样式),默认值:disabled -* anchor :锚点链接 -* onlyShowPreviousAndNext :是否只显示上一页和下一页(默认值为false,一般情况下在手机端才会把这个值设置true) -* previousText :上一页按钮的文本内容,默认值:上一页 -* nextText :下一页按钮的文本内容,默认值:下一页 - -##### #nextArticle() 指令的用法 - -指令 #nextArticle() 只能用于**文章详情页**,用于显示下一篇文章的相关信息或者内容。 - -```html -#nextArticle() -标题是:#(next.title ??) -#end -``` - -##### #previousArticle() 指令的用法 - -指令 #previousArticle() 只能用于**文章详情页**,用于显示上一篇文章的相关信息或者内容。 - -```html -#previousArticle() -标题是:#(previous.title ??) -#end -``` - - - -##### #categories() 指令的用法 - -指令 #categories() 可以在任意页面使用,用来读取分类的内容。 - -```html -#categories() - #for(category : categories) - #(category.title ??) - #end -#end -``` - -**指令#categories()的参数有** - -* flag :读取哪些flag的分类列表。 -* parentFlag :读取父级必须是该flag的分类列表。 -* asTree :是否以树状的数据进行返回,默认是false,返回全部分类。 - -##### #articleCategories() 指令的用法 - -指令 #articleCategories() 是用于读取某一篇文章的分类、或tag标签。 - -如下代码是用于读取文章的分类: - -```html -#articleCategories(article.id,"category") - #for(category : categories) - #(category.title ??) - #end -#end -``` - -如下代码是用于读取谋一篇文章的标签(一般用在文章列表循环里): - -```html -#articleCategories(article.id,"tag") - #for(category : categories) - #(category.title ??) - #end -#end -``` - - -**指令#articleCategories()的参数有** - -* articleCategories的使用必须传入两个值,顺序不能相反。第一个是文章的id,第二个是指定要获取文章分类的类型。 - - -##### #tags() 指令的用法 -```html -#tags() - #for(tag : tags) -
  • #(tag.title)
  • - #end -#end -``` - -**指令#tags() 的参数有** - -* orderBy : 排序方式 -* count : 数量 - - - -##### #page() 指令的用法 - -指令 #page() 可以用于任何页面,用于读取页面内容。 - -代码如下: - -```html -#page(slug=“about”) -这个页面的标题是:#(page.title ??) -这个页面的内容是:#(page.content ??) -#end -``` - -**指令#page()的参数有** - -* slug :page的唯一标识,在后台编辑页面的时候填写,如下图: - -![](./images/docimgs/page_about_slug.png) - -##### #pages() 指令的用法 - -指令 #pages() 可以用于任何页面,用于读取页面内容**列表**。 - -代码如下: - -```html -#pages() - #for(page : pages) - 这个页面的标题是:#(page.title ??) - 这个页面的内容是:#(page.content ??) - #end -#end -``` - -**指令#pages()的参数有** - -* flag :页面标志,可以在后台编辑页面的时候填写。通过flag,可以把几个页面归属到同一个flag,做到页面的“归类”作用。 - -##### #users() 指令的用法 - -暂未完成 - - - -## JPress二次开发 - -JPress 是一个内置了几乎任何互联网系统都必须模块: - -* 用户管理 -* 权限管理 -* 文章功能 -* 页面功能 -* 微信公众号对接 -* 微信小程序 -* API接口 -* 安全机制 -* ... - -目前、市面是几乎任何的互联网系统都应该具备以上几个功能,所以,通过JPress来做二次开发,是非常明智的选择。 - -另外,是基于JFinal 和 Jboot进行开发的,JFinal 连续在开源中国(oschina.net)获得了多年的 “最受欢迎的中国开源软件” 称号,Jboot 是基于JFinal的一个微服务框架,在1亿+用户量的商业产品得到了验证,稳定和安全。 - -通过 JPress 进行二次开发,也是非常容易的。 - -**JPress 架构图** - -![](./images/docimgs/jpress_framework.png) - -### 开始 -在开始 JPress 二次开发之前,有必要了解下JPress的目录结构: - - -| 目录 | 描述 | 备注 | -| --- | --- | --- | -| codegen | 代码生成器 | 开发的时候用与生成maven模块代码,运行时用不到该模块 | -| doc | 文档存放目录 | | -| jpress-commons | 工具类和公用代码 | | -| jpress-core | JPress的核心代码 | | -| jpress-model | JPress非业务实体类 | | -| jpress-service-api | JPress非业务 service 接口定义 | | -| jpress-service-provider | JPress非业务 service 接口实现 | | -| jpress-template | JPress的html模板 | | -| jpress-web | JPress非业务的web处理代码 | 包含了 Controller、指令等 | -| module-article | 文章模块代码 | | -| module-page | 页面模块代码 | | -| starter | undertow启动模块,开发的时候可以运行里面的 DevStarter.java 的main方法 | 编译的时候会 jpress 可执行程序 | -| starter-tomcat | tomcat 启动模块 | 编译的时候回生成 war 包,用于放在tomcat部署 | - - - -如果使用JPress来开发一个自己的程序呢 ?我们假设要使用 jpress 来开发一个小型的论坛。 - -主要有以下几个步骤: - -* 1、需求分析和建库建表 -* 2、通过 JPress 直接生成 maven 模块和相关基础代码 -* 3、通过 实现 ModuleListener 配置模块基本信息 -* 4、通过 注解 @AdminMenu 和 @UcenterMenu 配置后台和用户中心菜单 -* 5、编码实现模块基本逻辑 -* 6、修改maven配置并运行 - -**1、需求分析和建库建表** - -我们假设论坛有三个表、分表时论坛版块、帖子和帖子回复,因为jpress已经有用户表了,所以不再需要用户表。 - -为了能够讲清楚如何使用jpress进行二次开发,我们故意把论坛的版块功能给简化了,论坛版块暂时不支持子版块功能。 - -表名分别为:`club_category`、`club_post`、`club_post_comment`。 - - -**2、通过 JPress 直接生成 maven 模块和相关基础代码** - -我们在 jpress 项目的 starter 模块下,建立一个新的代码生成器,用于对社区模块的代码生成。 - -代码生成器如下: - -```java -public class PageModuleGenerator { - - - private static String dbUrl = "jdbc:mysql://127.0.0.1:3306/newjpress"; - private static String dbUser = "root"; - private static String dbPassword = "123456"; - - - private static String moduleName = "club"; - private static String dbTables = "club_category,club_post,club_post_comment"; - private static String modelPackage = "io.jpress.module.club.model"; - private static String servicePackage = "io.jpress.module.club.service"; - - public static void main(String[] args) { - - ModuleGenerator moduleGenerator = new ModuleGenerator(moduleName, dbUrl, dbUser, dbPassword, dbTables, modelPackage, servicePackage); - moduleGenerator.gen(); - - } -} -``` - -执行完 `main()` 方法后,会在当前目录下生产一个叫 club 的新的maven模块。 - -**3、通过 实现 ModuleListener 配置模块基本信息** - -我们自动生成的 `module-club-web` 模块里,建立一个 叫 `ClubModuleListener` 的类,实现`ModuleListener`接口。 - -代码如下: - -```java -public class ClubModuleListener implements ModuleListener { - - @Override - public String onRenderDashboardBox(Controller controller) { - //在这里配置后台首页的相关模块 - //代码可以参考 ArticleModuleLisenter - return null; - } - - @Override - public void onConfigAdminMenu(List adminMenus) { - //这里配置后台菜单 - //代码参考 ArticleModuleLisenter - } - - @Override - public void onConfigUcenterMenu(List ucenterMenus) { - //这里配置用户中心菜单 - //代码参考 ArticleModuleLisenter - } -} -``` -以上提到的`ArticleModuleLisenter`代码在: https://gitee.com/fuhai/jpress/blob/master/module-article/module-article-web/src/main/java/io/jpress/module/article/ArticleModuleLisenter.java - -**4、通过 @AdminMenu 和 @UcenterMenu 配置后台和用户中心菜单** - -我们来为club这个模块添加一个新的后台菜单,在这个之前,我们先来建立一个共识: - -* 1、菜单,肯定是一个可以访问的url地址。 -* 2、既然是可以访问的url地址,那么这个url地址肯定会对应某个Controller的某个方法。 - -因此,某个菜单,其实就是Controller的某个方法。 - -对于这个论坛系统,我们希望后台菜单显示如下: - -``` -论坛管理 ->>> 帖子列表 ->>> 回帖管理 ->>> 版块管理 -``` - -那么,我们需要建立一个叫 `_ClubController` 的类(名字任意取,后台相关的Controller,建议用下划线(_)开头,这样可以和 jpress 统一。) - -代码如下: - -```java -@RequestMapping("/admin/club") -public class _ClubController extends AdminControllerBase { - - @AdminMenu(text = "帖子列表", groupId = "club") - public void index() { - render("club/post_list.html"); - } - - @AdminMenu(text = "回帖管理", groupId = "club") - public void index() { - render("club/post_comment_list.html"); - } - - @AdminMenu(text = "版块管理", groupId = "club") - public void index() { - render("club/category_list.html"); - } -} -``` - -**注意:** - -* `@AdminMenu`里的`groupId`的值必须是`ClubModuleListener`里配置的id。如果我们把 `groupId` 修改为 `groupId = "page"`,那么此菜单将会被添加到后台的页 `页面管理` 这个菜单下面。 -* `_ClubController` 必须继承至 `AdminControllerBase`。 -* `@RequestMapping("/admin/club")`里的值必须是 `/admin/`开头。 - -**5、编码实现模块基本逻辑** - -暂略 - - -**6、修改maven配置并运行** - -默认情况下,此时通过 `mvn clean install` 进行进行编译,会出现maven编译错误。原因是代码生成器虽然生成了 club 模块,但是 club 模块依赖 `parent`, `module-club` 下的 pom 文件如下: - -```xml - - io.jpress - parent - 2.0 - -``` -maven 会去自动下载 io.jpress.parent 这个module,maven中央仓库上找不到这个 module 就会出现 maven编译错误。 - -因此,需要修改 jpress 根目录的 pom.xml ,添加把 `module-club` 添加到 pom.xml 里去,让 `module-club` 成为 jpress 的子模块。 - -如下代码: -``` - - - - module-article - module-page - - - module-club - - - -``` - -此时,如果直接运行starter模块下的main方法,也不到任何效果,原因是: - -* 1、starter 这个模块并未依赖你生成的 club 模块 -* 2、starter 里的resource并没有 club 模块的资源、比如html、css等。 - -所以,接下来我们需要修改 starter 的 `pom.xml` 文件,添加如下依赖。 - -```xml - - io.jpress - module-club-web - 2.0 - - - - io.jpress - module-club-service-provider - 2.0 - -``` - - -同时,为了让 maven 编译的时候,把 `club` 中的资源拷贝到 starter 里阿里。我们需要修改starter模块下的 pom.xml 的`maven-resources-plugin`插件配置为如下: - -```xml - - maven-resources-plugin - - - copy-resources - validate - - copy-resources - - - ${basedir}/target/classes/webapp - - - ${basedir}/../jpress-web/src/main/webapp - - - ${basedir}/../jpress-template/src/main/webapp - - - ${basedir}/../module-page/module-page-web/src/main/webapp - - - ${basedir}/../module-article/module-article-web/src/main/webapp - - - - - ${basedir}/../module-club/module-club-web/src/main/webapp - - - - - - - -``` - -此时,进行 `mvn clean install` 完毕之后,就可以正常运行了。 - -注意:`starter-tomcat` 模块也需要做如此配置。 - - -## 微信插件开发 - -在 jpress 里,做微信开发非常简单,直接看代码: - -```java -public class HelloWechatAddon implements WechatAddon { - - @Override - public boolean onMatchingMessage(InMsg inMsg, MsgController msgController) { - - return false; - } - - @Override - public boolean onRenderMessage(InMsg inMsg, MsgController msgController) { - - return true; - } -} -``` -**说明:** - -* 1、在任意maven module下,编写任意名称的类,实现WechatAddon接口。JPress 会自动扫描到该类,并添加到 JPress 的管理体系里去。 -* 2、复写方法`onMatchingMessage`和`onRenderMessage`。 - * onMatchingMessage :用来匹配是否是本插件要处理的消息 - * onRenderMessage :用来返回给微信客户端一个消息 - -* 3、添加 `@WechatAddonConfig` 注解的配置,用来给这个插件添加描述。 - -以下代码是完整的 hello world 例子,当用户在微信客客户端给公众号输入 `hello` 的时候,服务器给微信返回 `world` 字符串: - -```java -@WechatAddonConfig( - id = "ip.press.helloaddon", //这个插件的ID - title = "Hello World",//这个插件的标题,用于在后台显示 - description = "这是一个 Hello World 微信插件,方便开发参考。用户输入 hello,返回 world", //这个插件的描述 - author = "海哥" //这个插件的作者 -) -public class HelloWechatAddon implements WechatAddon { - - @Override - public boolean onMatchingMessage(InMsg inMsg, MsgController msgController) { - - //当用户给公众号发送的不是文本消息的时候 - //返回 false 不由本插件处理 - if (!(inMsg instanceof InTextMsg)) { - return false; - } - - InTextMsg inTextMsg = (InTextMsg) inMsg; - String content = inTextMsg.getContent(); - - //当用户输入的内容不是 hello 的时候 - //返回false,不由本插件处理 - return content != null && content.equalsIgnoreCase("hello"); - } - - - @Override - public boolean onRenderMessage(InMsg inMsg, MsgController msgController) { - - //创建一个新的文本消息 - //通过 msgController 进行渲染返回给用户 - OutTextMsg outTextMsg = new OutTextMsg(inMsg); - outTextMsg.setContent("world"); - msgController.render(outTextMsg); - - //返回 true,表示本插件已经成功处理该消息 - //若返回false,表示本插件处理消息失败,将会交给系统或者其他插件去处理 - return true; - } -} -``` -完整代码可以看这里:https://gitee.com/fuhai/jpress/blob/master/jpress-web/src/main/java/io/jpress/web/wechat/HelloWechatAddon.java - - -## JPress Http API - -### 配置相关API - -#### 获取配置信息 - -* 访问路径:/api/option -* 参数信息 - - -| 参数 | 描述 | 备注 | -| --- | --- | --- | -| key| 获取哪些key | 可以传入多个key,多个key用英文逗号隔开 | - -例如: - -http://127.0.0.1:8080/api/option?key=key1,key2 - -返回数据: - -```json - { - state : "ok", - data : { - key1: "data1", - key2: "data2" - } - } -``` - - -### 用户相关API - -#### 获取用户信息 -#### 注册用户 -#### 通过微信公众创建用户 -#### 通过微信小程序创建用户 - -通过微信小程序创建用户需要以下几个步骤。 - -**第一步:小程序端调用 wx.login() 之后获得 code** -**第二步:得到code之后,调用 jpress 的code2session接口** - -* 访问路径:/api/wechat/mp/code2session -* 参数信息 - - -| 参数 | 描述 | 备注 | -| --- | --- | --- | -| code| 通过 wx.login() 获得的code | | - -服务器相应内容如下: - -```json - { - state : "ok", - sessionId : "session_id_data" - } -``` - -**第三步:小程序调用wx.getUserInfo() 得到加密的用户数据** -**第四步:得到加密数据后,调用 jpress 的解密接口,得到用户ID** - -* 访问路径:/api/wechat/mp/decryptUserInfo -* 参数信息 - - -| 参数 | 描述 | 备注 | -| --- | --- | --- | -| rawData| 通过 wx.getUserInfo() 获得的| | -| signature| 通过 wx.getUserInfo() 获得的| | -| encryptedData| 通过 wx.getUserInfo() 获得的| | -| iv| 通过 wx.getUserInfo() 获得的| | -| sessionId| 通过第二步调用code2session接口获得的 | | - - -服务器相应内容如下: - -```json - { - state : "ok", - token : "token_data" - } -``` -token 非常重要,是用户的唯一标识。其数据是通过jwt进行加密得到的,客户端也可以通过jwt解密后得到原始的 userId。 - -小程序端的api,涉及到任何和用户相关的操作,都必须传此token进行用户验证。 - -备注:`/api/wechat/mp/decryptUserInfo`接口不仅仅是对用户数据进行解密,解密成功之后,会把数据存入数据库,得到的用户ID返回给客户端。 - - -### 文章相关API - -#### 获取文章详情 - -* 访问路径:/api/article -* 参数信息 - - -| 参数 | 描述 | 备注 | -| --- | --- | --- | -| id| 通过ID获取文章内容 | | -| slug| 通过slug获取文章内容 | | - -例如: - -http://127.0.0.1:8080/api/article?id=123 - -返回数据: - -```json - { -"state": "ok", -"article": { - "commentCount": 9, - "commentEnable": true, - "commentStatus": true, - "content": "文章内容\n", - "created": "2018-09-25 14:58:09", - "draft": false, - "editMode": "html", - "htmlView": "article.html", - "id": 20, - "modified": "2018-10-07 11:17:12", - "normal": true, - "orderNumber": 0, - "originalContent": "

    文章原始内容(这部分可能是markdown)\n", - "slug": "slug", - "status": "normal", - "text": "文本没人....", - "thumbnail": "/attachment/20181001/1a0fc4fa8e6e4fa8b11de48a362b92d2.png", - "title": "文章标题", - "trash": false, - "url": "/article/slug.html", - "userId": 1, - "viewCount": 328 - } -} -``` - -#### 获取文章类别 - -* 访问路径:/api/article/category -* 参数信息 - - -| 参数 | 描述 | 备注 | -| --- | --- | --- | -| id| 通过ID获取类别| | -| slug| 通过slug获取类别 | | -| type| 类别的类型 | 支持的参数有:`category`, `tag` | - -例如: - -http://127.0.0.1:8080/api/article/category?id=100 - -返回数据: - -```json - { -"state": "ok", -"category": { - "count": 0, - "htmlView": "artlist.html", - "id": 10, - "layerNumber": 0, - "layerString": "", - "modified": "2018-10-04 14:30:58", - "parentId": 0, - "pid": 0, - "slug": "keji", - "tag": false, - "title": "科技", - "top": true, - "type": "category", - "url": "/article/category/keji.html" - } -} -``` - - -### 页面相关API - - - -## 微信配置文档 - -### 微信公众号 - -微信公众号需要配置几个地方 - -**一、微信后台 -> 公众号设置 -> 功能设置** - -务必要保证以下三个填写了正确的域名: - -* 业务域名 -* JS接口安全域名 -* 网页授权域名 - -如下图所示: - -![](./images/docimgs/wechat_config1.jpg) - -**二、微信后台 -> 开发 -> 基本设置 -> 服务器配置** - -务必要保证以下三个地方填写正确: - -* URL:填写你的域名+'/wechat/msg' (这里非常重要) -* token:要保证和在你JPress后台填写的完全一致 -* 消息加解密方式:这里选择明文模式 - -如下图所示: - -![](./images/docimgs/wechat_config2.jpg) - -**三、微信后台 -> 开发 -> 基本设置 -> IP白名单** - -如下图所示,点击查看后,填写上 JPress 部署服务器的IP地址。 - -![](./images/docimgs/wechat_config3.jpg) - -### 微信小程序 - - +# JPress 文档 + + + +在使用JPress之前,你应该对数据库、服务器等有基本的认识。本文档是建立在这些基础知识之上的。 + +另外可以通过以下几种方式获得帮助: + +1. JPress官方公众号:jpressio +2. JPress交流QQ群:288397536 +3. 开源中国进行发帖提问。 + +## JPress安装 + +### 通过Docker进行安装 + +Linux : + +``` +wget https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml +docker-compose up -d +``` + +Mac OS : + +``` +curl -O https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml +docker-compose up -d +``` + +执行完毕以上命令之后,访问 `http://127.0.0.1:8080` 即可。 + +### 手动安装 + +JPress手动安装需要以下几个步骤: + +1. 下载JPress源码 +2. 通过maven编译JPress成war包(或可执行程序) +3. 启动JPress + +#### 1.下载JPress源码 + +下载JPress源码通过以下几种方式: + +1、git clone + +``` +git clone https://gitee.com/fuhai/jpress.git +``` + +2、进入 Gitee 的 JPress 发行页面进行下载 + +链接地址: https://gitee.com/fuhai/jpress/releases + +#### 2.通过Maven编译JPress成war包和可执行程序 + +JPress可以编译成war包和可执行程序,war需要在tomcat等web容器下运行。可执行程序内置undertow,不需要其他第三方web容器,运行脚本即可通过浏览器访问jpress应用。 + + +下载好 JPress 源码后,通过 shell 进入源码目录,执行如下 maven 命令: + +```shell +mvn package +``` + +稍等片刻,待命令执行完毕之后,即可在 `starter-tomcat/target` 目录下生成 `starter-tomcat-2.0.war` 的war包,在 `starter/target/` 目录下生成 starter-2.0 的文件夹,starter-2.0 文件夹的目录如下: + +``` +├── config +├── lib +├── webapp +├── jpress.sh +└── jpress.bat +``` + + 若编译不通过注意事项: + + * maven版本建议用3.0 以上,2.x没有测试过 + * java版本1.8 + * maven注意添加aliyun的源,修改 `maven/conf/setting.xml`文件,找到 mirrors 节点 ,修改如下: + + ```xml + + + alimaven + aliyun maven + http://maven.aliyun.com/nexus/content/groups/public/ + central + + + + ``` + + +#### 3、启动JPress + +##### 启动 jpress war 包 + +拷贝`starter-tomcat/target` 目录下的 `starter-tomcat-1.0.war` war包,放到tomcat的webapp目录下,手动解压缩。 + +启动tomcat(运行 `tomcat/bin/startup.sh`),浏览器输入 `http://127.0.0.1:8080/starter-tomcat-2.0` 即可访问。 + +若把 `tomcat/webapp/starter-tomcat-2.0` 里面的文件拷贝到 `tomcat/webapp/ROOT`,访问`http://127.0.0.1:8080`即可。 + + +##### 启动 jpress 可执行程序 + + +拷贝`starter/target/` 的 `starter-2.0` 目录,放到 Linux 上。 + + +执行 `./jpress.sh start` 脚本也可以启动jpress项目(window系统下执行 `./jpress.bat`)。 + + + +## 模板制作 + +JPress模板主要是由html、css、js和JPress标签组成,JPress标签的主要作用是用于读取后台数据,逻辑控制。 + +与此同时、JPress模板文件的文件名也是固定的,目录结构如下: + + +|模板文件| 描述 | 备注 | +| --- | --- | --- | +| index.html |首页模板| | +| error.html |错误页面模板| 当系统发生错误的时候,会自动调用此页面进行渲染,也可以扩展为 error_404.html,当发生404错误的时候优先使用此文件,同理可以扩展 error_500.html ,当系统发生500错误的时候调用此文件渲染。 | +| setting.html |后台的模板设置页面| 当次html不存在的时候,用户进入后台的模板设置,会显示此模板不支持设置功能 | +| screenshot.png |模板缩略图| 用于在后台的模板列表里显示的图片 | +| template.properties |模板信息描述文件| 文件格式在下方 | +| page.html |页面模块的模板| page.html 可以扩展为 page_aaa.html 、page_bbbb.html ,当模板扩展出 page_xxx.html 的时候,用户在后台发布页面内容的时候,就可以选择使用哪个模板样式进行渲染。例如: page_xxx.html 其中 `xxx` 为样式的名称。| +| article.html | 文章详情模板| 和page模块一样,article.html 可以扩展出 article_styel1.html、article_style2.html,这样,用户在后台发布文章的时候,可以选择文章样式。(备注:用户中心投稿不能选择样式) | +| artlist.html | 文章列表模板| 和page、article一样,可以通过样式 | +| artsearch.html | 文章搜索模板| 和page、article一样,可以通过样式 | +| user_login.html | 用户登录页面| JPress已经内置了登录页面,但是,当模板下有 user_login.html 的时候,就会自动使用模板下的这个页面来渲染 | +| user_register.html | 用注册页面| 用法通 user_login.html | + + +备注:所有的模板文件都可以扩展出专门用于渲染手机浏览器的模板。 + +例如:首页的渲染模板是 `index.html` ,如果当前目录下有 `index_h5.html`,那么,当用户通过手机访问网站的时候,JPress 会自动使用 `index_h5.html` 去渲染。 page 和 article、artlist 同理。 + +template.properties 文件配置如下 + +``` +id = cn.jeanstudio.bluelight +title = BlueLight +description = BlueLight是JeanStudio工作室为JPress设计的官网模板 +anthor = jeanStudio +authorWebsite = http://www.jeanstudio.cn +version = 1.0 +versionCode = 1 +updateUrl = +screenshot = screenshot.png +``` + +* id :模板ID,全网唯一,建议用域名+名称的命名方式 +* title :模板名称 +* description :模板简介 +* anthor :模板作者 +* authorWebsite :模板作者的官网 +* version :版本(不添加默认为1.0.0) +* versionCode :版本号(只能是数字,不填写默认为1) +* updateUrl :此模板升级的url地址 +* screenshot :此模板的缩略图图片(不填写默认为:screenshot.png) + + + + +#### 模板标签 + +有了以上这些目录结构,实际上不用任何的标签就可以成为一套模板了,只是这个模板是静态模板,不能读取后台数据。 + +只有通过在静态的html上,添加 JPress 标签,才能可以读取后台数据。 + +目前,JPress内置的模板标签如下: + +**1、全局标签,全局标签用全用大写显示,全局标签在任意模板页面都可以使用。** + +| 标签名称 | 数据类型 | 标签描述 | +| --- | --- | --- | +| #(WEB_NAME ??) | 字符串 | 网站名称 | +| #(WEB_TITLE ??) | 字符串 | 网站标题 | +| #(WEB_SUBTITLE ??) | 字符串 | 网站副标题 | +| #(WEB_DOMAIN ??) | 字符串 | 网站域名 | +| #(WEB_COPYRIGHT ??) | 字符串 | 网站版权信息 | +| #(SEO_TITLE ??) | 字符串 | 网站SEO标题 | +| #(SEO_KEYWORDS ??) | 字符串 | 网站SEO关键字 | +| #(SEO_DESCRIPTION ??) | 字符串 | 网站SEO描述 | +| MENUS | 数据列表( list ) | 菜单数据 | + +标签描述,标签建议用 `#( 名称 ??)` 的方式来读取数据,而不是用 `#(名称)` 两个问号(??)的意思是如果 后台填写的名称为空格,那么就用 两个问号(??)之后的内容来显示。 + +例如: +`#(WEB_NAME ??)` 表示优先使用 WEB_NAME 来显示,但是当 WEB_NAME 为空的时候,显示空数据(因为两个问好(??)之后的内容为空)。 + +`#(WEB_NAME ?? WEB_TITLE)` 表示优先使用 WEB_NAME 来显示,但是当 WEB_NAME 为空的时候,用 WEB_TITLE(网站标题) 来显示。 + +`#(SEO_TITLE ?? WEB_TITLE +'-'+ WEB_SUBTITLE)` 表示优先使用 SEO_TITLE(SEO标题) 来显示,但是当 SEO_TITLE 为空的时候,用 `WEB_TITLE - WEB_SUBTITLE` 来显示。 + +有了以上知识后,我们的 index.html 首页模板文件可以如下: + +```html + + + + #(SEO_TITLE ?? (WEB_TITLE + '-' + WEB_SUBTITLE)) + + + + +这是首页.... + + +``` + +以上内容都只是针对 `字符串` 这种数据类型进行展示的,全局标签中还有一种数据类型叫 `数据列表( list )`,那么,怎么来显示数据列表呢? + +这个时候`#( 名称 ??)`就不能正常显示了,需要用到一个新的标签: + +```html +#for +... +#end +``` + +`#for ... #end` 标签也叫循环标签,意思是把列表循环显示出来。 + +对于 `MENUS` 这种数据类型为 `数据列表( list )` 的数据,`#for ... #end` 标签使用如下。 + + +```html +#for(menu : MENUS) +

  • #(menu.text ??)
  • +#end +``` + +这样,若我们在后台创建了5个菜单,那么html会输出 5个 `
  • ...
  • ` + +对于以上的菜单显示,还有一个问题就是如何显示二级菜单呢? + +代码如下: + +```html +#for(menu : MENUS) +
  • #(menu.text ??)
  • + #if(menu.hasChild()) +
    + #for(childMenu : menu.getChilds()) +
  • #(menu.text ??)
  • + #end +
    + #end +#end +``` + +以上代码显示了所有菜单的的二级菜单,但是,有些时候我们想在网站的某些位置,显示 **当前菜单** 下的子菜单,如何做呢? + + +代码如下: + +```html +#for(me: MENUS) + #if(me.isActive && me.hasChild()) + + + #end +#end +``` + + + +**2、数据指令,数据指令一般情况下只能用于特有页面** + +文章相关指令: + +| 指令名称 | 可用页面 |描述 | +| --- | --- | --- | +| #article() | 任意 | 用于读取特定的单篇文章 | +| #articles() | 任意 | 用于读取文章列表,例如:热门文章文章、最新评论文章列表等等 | +| #tagArticles() | 任意 | 读取某个tag下的文章列表 | +| #categoryArticles() | 任意 | 读取某个分类下的文章列表 | +| #articlePage() | 任意 | 用于对文章列表进行的内容和分页进行显示 | +| #commentPage() | 文章详情:article.html | 用于对文章评论的内容和分页进行显示 | +| #nextArticle() | 文章详情:article.html | 下一篇文章 | +| #previousArticle() | 文章详情:article.html | 上一篇文章 | +| #relevantArticles() | 文章详情:article.html | 相关文章列表,相同标签的的文章 | +| #categories() | 任意 | 读取文章模块的所有分类 | +| #tags() | 任意 | 用于读取文章标签 | +| #articleCategories() | 任意 | 用于读取某一篇文章的所属分类,例如:文章的标签、文章的分类等 | +| #articleSearchPage() | 文章搜索结果页 artsearch.html | 用于渲染搜索结果 | + + +产品相关指令: + +| 指令名称 | 可用页面 |描述 | +| --- | --- | --- | +| #products() | 任意 | 获取产品的列表 | +| #categoryProducts() | 任意 | 用根据分类获取产品内容 | +| #nextProduct() | 产品详情:product.htm | 下一个产品 | +| #previousProduct() | 产品详情:product.htm| 上一个产品 | +| #productCategories() | 任意 | 获取某个产品对应的分类或者标签 | +| #productCategoryList() | 任意 | 产品分类列表 | +| #productCommentPage() | 产品详情:product.htm | 产品评论分页 | +| #product() | 任意 | 根据产品id或者slug读取产品信息 | +| #productPage() | 任意 | 产品分页 | +| #productSearchPage() | 任意 | 产品搜索分页 | +| #productTags() | 任意 | 产品标签 | +| #relevantProducts() | 任意 | 某个产品的相关产品(相同tag的产品) | + + + +页面相关指令: + +| 指令名称 | 可用页面 |描述 | +| --- | --- | --- | +| #page() | 任意 | 用于读取某个页面 | +| #pages() | 任意 | 用于读取页面列表 | + + + 用户相关指令: + +| 指令名称 | 可用页面 |描述 | +| --- | --- | --- | +| #users() | 暂不支持 | 用于读取页面列表 | + + +##### #article() 指令的用法 + +此指令是用来读取一篇文章,网站的任意页面进行展示。 + +```html +#article() +#(article.title) +
    #(article.content)
    +#end +``` + +##### #articles() 指令的用法 + +此指令是在任何页面,用来读取文章列表。例如:最新文章、热门文章等 + +```html +#articles(flag="",hasThumbnail="",orderBy="",count=10) + #for(article : articles) + #(article.title) + #end +#end +``` + +**#articles() 指令支持的参数有:** + +* flag:文章标识,这个是在编辑文章的时候自由填写。 +* hasThumbnail:是否需要缩略图,值为 true 和 false。 +* orderBy :根据什么进行排序,目前支持的值有:order_number(用户自定义排序)、comment_count(文章的评论数量)、comment_time(文章的评论时间)、view_count(文章的访问量)、created(文章的创建时间)、modified(文章的修改时间) +* count :要显示多少篇文章 +* style :文章样式 + +##### #tagArticles() 指令的用法 + +此指令是在任何页面,用来读取文章列表。例如:最新文章、热门文章等 + +```html +#tagArticles(tag="aaa",hasThumbnail="",orderBy="",count=10) + #for(article : articles) + #(article.title) + #end +#end +``` + +**#tagArticles() 指令支持的参数有:** + +* tag:哪个tag。 +* hasThumbnail:是否需要缩略图,值为 true 和 false。 +* orderBy :根据什么进行排序,目前支持的值有:order_number(用户自定义排序)、comment_count(文章的评论数量)、comment_time(文章的评论时间)、view_count(文章的访问量)、created(文章的创建时间)、modified(文章的修改时间) +* count :要显示多少篇文章 + +##### #categoryArticles() 指令的用法 + +此指令是在任何页面,用来读取文章列表。例如:最新文章、热门文章等 + +```html +#categoryArticles(categoryFlag="",hasThumbnail="",orderBy="",count="") + #for(article : articles) + #(article.title) + #end +#end +``` + +**#categoryArticles() 指令支持的参数有:** + +* categoryFlag:分类的标识。 +* hasThumbnail:是否需要缩略图,值为 true 和 false。 +* orderBy :根据什么进行排序,目前支持的值有:order_number(用户自定义排序)、comment_count(文章的评论数量)、comment_time(文章的评论时间)、view_count(文章的访问量)、created(文章的创建时间)、modified(文章的修改时间) +* count :要显示多少篇文章 + +##### #articlePage() 指令的用法 +指令 #articlePage() 只能用在文章列表页,也就是 artlist.html 模板文件及其扩展文件。 + +```java +#articlePage() + + #for(article : articlePage.list) + + 文章标题是:#(article.title ??) + +
    + 文章内容是:#maxLength(article.text,100) +
    + #end + + #articlePaginate() + #for(page : pages) + + #(page.text ??) + + #end + #end + +#end +``` +**说明** +指令 #articlePage() 内部又包含了另一个指令 #articlePaginate(),#articlePaginate()是用于显示上一页和下一下。 + +**指令 #articlePage() 的参数有:** + +* pageSize :可以用来指定当前页面有多少条数据,默认值是:10。也就是说 `#articlePage()` 等同于 `#articlePage(pageSize=10)` + +**分页指令#articlePaginate()的参数有** + +* previousClass :上一页的样式,默认值:previous +* nextClass :下一页的样式,默认值:next +* activeClass :当前页面的样式,默认值:active +* disabledClass :禁用的样式(当下一页没有数据的时候,会使用此样式),默认值:disabled +* anchor :锚点链接 +* onlyShowPreviousAndNext :是否只显示上一页和下一页(默认值为false,一般情况下在手机端才会把这个值设置true) +* previousText :上一页按钮的文本内容,默认值:上一页 +* nextText :下一页按钮的文本内容,默认值:下一页 +* firstGotoIndex : 是否让第一页进入首页,默认值:false + +##### #commentPage()指令的用法 + +指令 #commentPage() 只能用在文章详情页,也就是 article.html 模板文件及其扩展文件。用于读取这篇文章的相关评论信息以及评论的分页功能。 + +```html +#commentPage() + + #for(comment : commentPage.list) +
    评论内容是:#(comment.content ??)
    +
    评论作者是:#(comment.authro ??)
    + #end + + #commentPaginate() + #for(page : pages) + + #(page.text ??) + + #end + #end + +#end +``` +**说明** +和一样#articlePage(),#commentPage()指令 内部又包含了另一个指令 #commentPaginate(),#commentPaginate()是用于显示评论的上一页和下一下。 + +**指令 #commentPage() 的参数有:** + +* pageSize :可以用来指定当前文章详情,每页的评论条数是多少,默认值是:10。也就是说 `#commentPage()` 等同于 `#commentPage(pageSize=10)` + +**分页指令#commentPaginate()的参数有** + +* previousClass :上一页的样式,默认值:previous +* nextClass :下一页的样式,默认值:next +* activeClass :当前页面的样式,默认值:active +* disabledClass :禁用的样式(当下一页没有数据的时候,会使用此样式),默认值:disabled +* anchor :锚点链接 +* onlyShowPreviousAndNext :是否只显示上一页和下一页(默认值为false,一般情况下在手机端才会把这个值设置true) +* previousText :上一页按钮的文本内容,默认值:上一页 +* nextText :下一页按钮的文本内容,默认值:下一页 + +##### #nextArticle() 指令的用法 + +指令 #nextArticle() 只能用于**文章详情页**,用于显示下一篇文章的相关信息或者内容。 + +```html +#nextArticle() +标题是:#(next.title ??) +#end +``` + +##### #previousArticle() 指令的用法 + +指令 #previousArticle() 只能用于**文章详情页**,用于显示上一篇文章的相关信息或者内容。 + +```html +#previousArticle() +标题是:#(previous.title ??) +#end +``` + + + +##### #categories() 指令的用法 + +指令 #categories() 可以在任意页面使用,用来读取分类的内容。 + +```html +#categories() + #for(category : categories) + #(category.title ??) + #end +#end +``` + +**指令#categories()的参数有** + +* flag :读取哪些flag的分类列表。 +* parentFlag :读取父级必须是该flag的分类列表。 +* asTree :是否以树状的数据进行返回,默认是false,返回全部分类。 + +##### #articleCategories() 指令的用法 + +指令 #articleCategories() 是用于读取某一篇文章的分类、或tag标签。 + +如下代码是用于读取文章的分类: + +```html +#articleCategories(article.id,"category") + #for(category : categories) + #(category.title ??) + #end +#end +``` + +如下代码是用于读取谋一篇文章的标签(一般用在文章列表循环里): + +```html +#articleCategories(article.id,"tag") + #for(category : categories) + #(category.title ??) + #end +#end +``` + + +**指令#articleCategories()的参数有** + +* articleCategories的使用必须传入两个值,顺序不能相反。第一个是文章的id,第二个是指定要获取文章分类的类型。 + + +##### #tags() 指令的用法 +```html +#tags() + #for(tag : tags) +
  • #(tag.title)
  • + #end +#end +``` + +**指令#tags() 的参数有** + +* orderBy : 排序方式 +* count : 数量 + + + +##### #page() 指令的用法 + +指令 #page() 可以用于任何页面,用于读取页面内容。 + +代码如下: + +```html +#page(slug=“about”) +这个页面的标题是:#(page.title ??) +这个页面的内容是:#(page.content ??) +#end +``` + +**指令#page()的参数有** + +* slug :page的唯一标识,在后台编辑页面的时候填写,如下图: + +![](./images/docimgs/page_about_slug.png) + +##### #pages() 指令的用法 + +指令 #pages() 可以用于任何页面,用于读取页面内容**列表**。 + +代码如下: + +```html +#pages() + #for(page : pages) + 这个页面的标题是:#(page.title ??) + 这个页面的内容是:#(page.content ??) + #end +#end +``` + +**指令#pages()的参数有** + +* flag :页面标志,可以在后台编辑页面的时候填写。通过flag,可以把几个页面归属到同一个flag,做到页面的“归类”作用。 + +##### #users() 指令的用法 + +暂未完成 + + + +## JPress二次开发 + +JPress 是一个内置了几乎任何互联网系统都必须模块: + +* 用户管理 +* 权限管理 +* 文章功能 +* 页面功能 +* 微信公众号对接 +* 微信小程序 +* API接口 +* 安全机制 +* ... + +目前、市面是几乎任何的互联网系统都应该具备以上几个功能,所以,通过JPress来做二次开发,是非常明智的选择。 + +另外,是基于JFinal 和 Jboot进行开发的,JFinal 连续在开源中国(oschina.net)获得了多年的 “最受欢迎的中国开源软件” 称号,Jboot 是基于JFinal的一个微服务框架,在1亿+用户量的商业产品得到了验证,稳定和安全。 + +通过 JPress 进行二次开发,也是非常容易的。 + +**JPress 架构图** + +![](./images/docimgs/jpress_framework.png) + +### 开始 +在开始 JPress 二次开发之前,有必要了解下JPress的目录结构: + + +| 目录 | 描述 | 备注 | +| --- | --- | --- | +| codegen | 代码生成器 | 开发的时候用与生成maven模块代码,运行时用不到该模块 | +| doc | 文档存放目录 | | +| jpress-commons | 工具类和公用代码 | | +| jpress-core | JPress的核心代码 | | +| jpress-model | JPress非业务实体类 | | +| jpress-service-api | JPress非业务 service 接口定义 | | +| jpress-service-provider | JPress非业务 service 接口实现 | | +| jpress-template | JPress的html模板 | | +| jpress-web | JPress非业务的web处理代码 | 包含了 Controller、指令等 | +| module-article | 文章模块代码 | | +| module-page | 页面模块代码 | | +| starter | undertow启动模块,开发的时候可以运行里面的 DevStarter.java 的main方法 | 编译的时候会 jpress 可执行程序 | +| starter-tomcat | tomcat 启动模块 | 编译的时候回生成 war 包,用于放在tomcat部署 | + + + +如果使用JPress来开发一个自己的程序呢 ?我们假设要使用 jpress 来开发一个小型的论坛。 + +主要有以下几个步骤: + +* 1、需求分析和建库建表 +* 2、通过 JPress 直接生成 maven 模块和相关基础代码 +* 3、通过 实现 ModuleListener 配置模块基本信息 +* 4、通过 注解 @AdminMenu 和 @UcenterMenu 配置后台和用户中心菜单 +* 5、编码实现模块基本逻辑 +* 6、修改maven配置并运行 + +**1、需求分析和建库建表** + +我们假设论坛有三个表、分表时论坛版块、帖子和帖子回复,因为jpress已经有用户表了,所以不再需要用户表。 + +为了能够讲清楚如何使用jpress进行二次开发,我们故意把论坛的版块功能给简化了,论坛版块暂时不支持子版块功能。 + +表名分别为:`club_category`、`club_post`、`club_post_comment`。 + + +**2、通过 JPress 直接生成 maven 模块和相关基础代码** + +我们在 jpress 项目的 starter 模块下,建立一个新的代码生成器,用于对社区模块的代码生成。 + +代码生成器如下: + +```java +public class PageModuleGenerator { + + + private static String dbUrl = "jdbc:mysql://127.0.0.1:3306/newjpress"; + private static String dbUser = "root"; + private static String dbPassword = "123456"; + + + private static String moduleName = "club"; + private static String dbTables = "club_category,club_post,club_post_comment"; + private static String modelPackage = "io.jpress.module.club.model"; + private static String servicePackage = "io.jpress.module.club.service"; + + public static void main(String[] args) { + + ModuleGenerator moduleGenerator = new ModuleGenerator(moduleName, dbUrl, dbUser, dbPassword, dbTables, modelPackage, servicePackage); + moduleGenerator.gen(); + + } +} +``` + +执行完 `main()` 方法后,会在当前目录下生产一个叫 club 的新的maven模块。 + +**3、通过 实现 ModuleListener 配置模块基本信息** + +我们自动生成的 `module-club-web` 模块里,建立一个 叫 `ClubModuleListener` 的类,实现`ModuleListener`接口。 + +代码如下: + +```java +public class ClubModuleListener implements ModuleListener { + + @Override + public String onRenderDashboardBox(Controller controller) { + //在这里配置后台首页的相关模块 + //代码可以参考 ArticleModuleLisenter + return null; + } + + @Override + public void onConfigAdminMenu(List adminMenus) { + //这里配置后台菜单 + //代码参考 ArticleModuleLisenter + } + + @Override + public void onConfigUcenterMenu(List ucenterMenus) { + //这里配置用户中心菜单 + //代码参考 ArticleModuleLisenter + } +} +``` +以上提到的`ArticleModuleLisenter`代码在: https://gitee.com/fuhai/jpress/blob/master/module-article/module-article-web/src/main/java/io/jpress/module/article/ArticleModuleLisenter.java + +**4、通过 @AdminMenu 和 @UcenterMenu 配置后台和用户中心菜单** + +我们来为club这个模块添加一个新的后台菜单,在这个之前,我们先来建立一个共识: + +* 1、菜单,肯定是一个可以访问的url地址。 +* 2、既然是可以访问的url地址,那么这个url地址肯定会对应某个Controller的某个方法。 + +因此,某个菜单,其实就是Controller的某个方法。 + +对于这个论坛系统,我们希望后台菜单显示如下: + +``` +论坛管理 +>>> 帖子列表 +>>> 回帖管理 +>>> 版块管理 +``` + +那么,我们需要建立一个叫 `_ClubController` 的类(名字任意取,后台相关的Controller,建议用下划线(_)开头,这样可以和 jpress 统一。) + +代码如下: + +```java +@RequestMapping("/admin/club") +public class _ClubController extends AdminControllerBase { + + @AdminMenu(text = "帖子列表", groupId = "club") + public void index() { + render("club/post_list.html"); + } + + @AdminMenu(text = "回帖管理", groupId = "club") + public void index() { + render("club/post_comment_list.html"); + } + + @AdminMenu(text = "版块管理", groupId = "club") + public void index() { + render("club/category_list.html"); + } +} +``` + +**注意:** + +* `@AdminMenu`里的`groupId`的值必须是`ClubModuleListener`里配置的id。如果我们把 `groupId` 修改为 `groupId = "page"`,那么此菜单将会被添加到后台的页 `页面管理` 这个菜单下面。 +* `_ClubController` 必须继承至 `AdminControllerBase`。 +* `@RequestMapping("/admin/club")`里的值必须是 `/admin/`开头。 + +**5、编码实现模块基本逻辑** + +暂略 + + +**6、修改maven配置并运行** + +默认情况下,此时通过 `mvn clean install` 进行进行编译,会出现maven编译错误。原因是代码生成器虽然生成了 club 模块,但是 club 模块依赖 `parent`, `module-club` 下的 pom 文件如下: + +```xml + + io.jpress + parent + 2.0 + +``` +maven 会去自动下载 io.jpress.parent 这个module,maven中央仓库上找不到这个 module 就会出现 maven编译错误。 + +因此,需要修改 jpress 根目录的 pom.xml ,添加把 `module-club` 添加到 pom.xml 里去,让 `module-club` 成为 jpress 的子模块。 + +如下代码: +``` + + + + module-article + module-page + + + module-club + + + +``` + +此时,如果直接运行starter模块下的main方法,也不到任何效果,原因是: + +* 1、starter 这个模块并未依赖你生成的 club 模块 +* 2、starter 里的resource并没有 club 模块的资源、比如html、css等。 + +所以,接下来我们需要修改 starter 的 `pom.xml` 文件,添加如下依赖。 + +```xml + + io.jpress + module-club-web + 2.0 + + + + io.jpress + module-club-service-provider + 2.0 + +``` + + +同时,为了让 maven 编译的时候,把 `club` 中的资源拷贝到 starter 里阿里。我们需要修改starter模块下的 pom.xml 的`maven-resources-plugin`插件配置为如下: + +```xml + + maven-resources-plugin + + + copy-resources + validate + + copy-resources + + + ${basedir}/target/classes/webapp + + + ${basedir}/../jpress-web/src/main/webapp + + + ${basedir}/../jpress-template/src/main/webapp + + + ${basedir}/../module-page/module-page-web/src/main/webapp + + + ${basedir}/../module-article/module-article-web/src/main/webapp + + + + + ${basedir}/../module-club/module-club-web/src/main/webapp + + + + + + + +``` + +此时,进行 `mvn clean install` 完毕之后,就可以正常运行了。 + +注意:`starter-tomcat` 模块也需要做如此配置。 + + +## 微信插件开发 + +在 jpress 里,做微信开发非常简单,直接看代码: + +```java +public class HelloWechatAddon implements WechatAddon { + + @Override + public boolean onMatchingMessage(InMsg inMsg, MsgController msgController) { + + return false; + } + + @Override + public boolean onRenderMessage(InMsg inMsg, MsgController msgController) { + + return true; + } +} +``` +**说明:** + +* 1、在任意maven module下,编写任意名称的类,实现WechatAddon接口。JPress 会自动扫描到该类,并添加到 JPress 的管理体系里去。 +* 2、复写方法`onMatchingMessage`和`onRenderMessage`。 + * onMatchingMessage :用来匹配是否是本插件要处理的消息 + * onRenderMessage :用来返回给微信客户端一个消息 + +* 3、添加 `@WechatAddonConfig` 注解的配置,用来给这个插件添加描述。 + +以下代码是完整的 hello world 例子,当用户在微信客客户端给公众号输入 `hello` 的时候,服务器给微信返回 `world` 字符串: + +```java +@WechatAddonConfig( + id = "ip.press.helloaddon", //这个插件的ID + title = "Hello World",//这个插件的标题,用于在后台显示 + description = "这是一个 Hello World 微信插件,方便开发参考。用户输入 hello,返回 world", //这个插件的描述 + author = "海哥" //这个插件的作者 +) +public class HelloWechatAddon implements WechatAddon { + + @Override + public boolean onMatchingMessage(InMsg inMsg, MsgController msgController) { + + //当用户给公众号发送的不是文本消息的时候 + //返回 false 不由本插件处理 + if (!(inMsg instanceof InTextMsg)) { + return false; + } + + InTextMsg inTextMsg = (InTextMsg) inMsg; + String content = inTextMsg.getContent(); + + //当用户输入的内容不是 hello 的时候 + //返回false,不由本插件处理 + return content != null && content.equalsIgnoreCase("hello"); + } + + + @Override + public boolean onRenderMessage(InMsg inMsg, MsgController msgController) { + + //创建一个新的文本消息 + //通过 msgController 进行渲染返回给用户 + OutTextMsg outTextMsg = new OutTextMsg(inMsg); + outTextMsg.setContent("world"); + msgController.render(outTextMsg); + + //返回 true,表示本插件已经成功处理该消息 + //若返回false,表示本插件处理消息失败,将会交给系统或者其他插件去处理 + return true; + } +} +``` +完整代码可以看这里:https://gitee.com/fuhai/jpress/blob/master/jpress-web/src/main/java/io/jpress/web/wechat/HelloWechatAddon.java + + +## JPress Http API + +### 配置相关API + +#### 获取配置信息 + +* 访问路径:/api/option +* 参数信息 + + +| 参数 | 描述 | 备注 | +| --- | --- | --- | +| key| 获取哪些key | 可以传入多个key,多个key用英文逗号隔开 | + +例如: + +http://127.0.0.1:8080/api/option?key=key1,key2 + +返回数据: + +```json + { + state : "ok", + data : { + key1: "data1", + key2: "data2" + } + } +``` + + +### 用户相关API + +#### 获取用户信息 +#### 注册用户 +#### 通过微信公众创建用户 +#### 通过微信小程序创建用户 + +通过微信小程序创建用户需要以下几个步骤。 + +**第一步:小程序端调用 wx.login() 之后获得 code** +**第二步:得到code之后,调用 jpress 的code2session接口** + +* 访问路径:/api/wechat/mp/code2session +* 参数信息 + + +| 参数 | 描述 | 备注 | +| --- | --- | --- | +| code| 通过 wx.login() 获得的code | | + +服务器相应内容如下: + +```json + { + state : "ok", + sessionId : "session_id_data" + } +``` + +**第三步:小程序调用wx.getUserInfo() 得到加密的用户数据** +**第四步:得到加密数据后,调用 jpress 的解密接口,得到用户ID** + +* 访问路径:/api/wechat/mp/decryptUserInfo +* 参数信息 + + +| 参数 | 描述 | 备注 | +| --- | --- | --- | +| rawData| 通过 wx.getUserInfo() 获得的| | +| signature| 通过 wx.getUserInfo() 获得的| | +| encryptedData| 通过 wx.getUserInfo() 获得的| | +| iv| 通过 wx.getUserInfo() 获得的| | +| sessionId| 通过第二步调用code2session接口获得的 | | + + +服务器相应内容如下: + +```json + { + state : "ok", + token : "token_data" + } +``` +token 非常重要,是用户的唯一标识。其数据是通过jwt进行加密得到的,客户端也可以通过jwt解密后得到原始的 userId。 + +小程序端的api,涉及到任何和用户相关的操作,都必须传此token进行用户验证。 + +备注:`/api/wechat/mp/decryptUserInfo`接口不仅仅是对用户数据进行解密,解密成功之后,会把数据存入数据库,得到的用户ID返回给客户端。 + + +### 文章相关API + +#### 获取文章详情 + +* 访问路径:/api/article +* 参数信息 + + +| 参数 | 描述 | 备注 | +| --- | --- | --- | +| id| 通过ID获取文章内容 | | +| slug| 通过slug获取文章内容 | | + +例如: + +http://127.0.0.1:8080/api/article?id=123 + +返回数据: + +```json + { +"state": "ok", +"article": { + "commentCount": 9, + "commentEnable": true, + "commentStatus": true, + "content": "文章内容\n", + "created": "2018-09-25 14:58:09", + "draft": false, + "editMode": "html", + "htmlView": "article.html", + "id": 20, + "modified": "2018-10-07 11:17:12", + "normal": true, + "orderNumber": 0, + "originalContent": "

    文章原始内容(这部分可能是markdown)\n", + "slug": "slug", + "status": "normal", + "text": "文本没人....", + "thumbnail": "/attachment/20181001/1a0fc4fa8e6e4fa8b11de48a362b92d2.png", + "title": "文章标题", + "trash": false, + "url": "/article/slug.html", + "userId": 1, + "viewCount": 328 + } +} +``` + +#### 获取文章类别 + +* 访问路径:/api/article/category +* 参数信息 + + +| 参数 | 描述 | 备注 | +| --- | --- | --- | +| id| 通过ID获取类别| | +| slug| 通过slug获取类别 | | +| type| 类别的类型 | 支持的参数有:`category`, `tag` | + +例如: + +http://127.0.0.1:8080/api/article/category?id=100 + +返回数据: + +```json + { +"state": "ok", +"category": { + "count": 0, + "htmlView": "artlist.html", + "id": 10, + "layerNumber": 0, + "layerString": "", + "modified": "2018-10-04 14:30:58", + "parentId": 0, + "pid": 0, + "slug": "keji", + "tag": false, + "title": "科技", + "top": true, + "type": "category", + "url": "/article/category/keji.html" + } +} +``` + + +### 页面相关API + + + +## 微信配置文档 + +### 微信公众号 + +微信公众号需要配置几个地方 + +**一、微信后台 -> 公众号设置 -> 功能设置** + +务必要保证以下三个填写了正确的域名: + +* 业务域名 +* JS接口安全域名 +* 网页授权域名 + +如下图所示: + +![](./images/docimgs/wechat_config1.jpg) + +**二、微信后台 -> 开发 -> 基本设置 -> 服务器配置** + +务必要保证以下三个地方填写正确: + +* URL:填写你的域名+'/wechat/msg' (这里非常重要) +* token:要保证和在你JPress后台填写的完全一致 +* 消息加解密方式:这里选择明文模式 + +如下图所示: + +![](./images/docimgs/wechat_config2.jpg) + +**三、微信后台 -> 开发 -> 基本设置 -> IP白名单** + +如下图所示,点击查看后,填写上 JPress 部署服务器的IP地址。 + +![](./images/docimgs/wechat_config3.jpg) + +### 微信小程序 + + diff --git a/doc/template_dev.md b/doc/template_dev.md index b19eaebe6533271cb458b2d8e8e5d37189a6fc00..50331ef0c150daf810df56202e529ca7512d48a6 100644 --- a/doc/template_dev.md +++ b/doc/template_dev.md @@ -1,292 +1,292 @@ -# 模板开发 - -## 目录 - -- 模板开发准备 -- 模板的组成 -- 模板的目录结构 -- 模板的多样式 -- 模板的手机版样式 -- 模板引擎指令 -- 模板标签 -- 模板的安装和卸载 - -## 模板开发准备 - -**1、安装Docker** - -JPress 模板开发准备,主要是准备 docker 环境,Docker 的安装可以参考一下链接: - -* [Mac](https://docs.docker.com/docker-for-mac/install) -* [Windows](https://docs.docker.com/docker-for-windows/install) -* [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu) -* [Debian](https://docs.docker.com/install/linux/docker-ce/debian) -* [CentOS](https://docs.docker.com/install/linux/docker-ce/centos) -* [Fedora](https://docs.docker.com/install/linux/docker-ce/fedora) -* [其他 Linux 发行版](https://docs.docker.com/install/linux/docker-ce/binaries) - -Docker 的安装过程略,一般情况下都是安装比较顺利的,若安装处错自行搜索引擎查询下。 - -**2、通过Docker运行JPress** - -Docker 安装完毕后,下载文件 https://gitee.com/fuhai/jpress/raw/v2.0/docker-compose-for-dev.yml 到本地。(打开此链接,然后右键另存为... 或者按快捷键 `ctrl+s` 保存到本地,mac系统的快捷键是`command+s`) - -下载完毕后,重命名刚刚下载文件 `docker-compose-for-dev.yml` 为 `docker-compose.yml` ,并把 `docker-compose.yml` 放入提前建好的文件夹中。 - -然后通过 shell ( window系统是cmd )进入该文件夹,执行如下命令: - -`docker-compose up -d` - -**Shell小知识** ->如何用命令进入某个文件夹? ->答:进入文件夹的命令是: `cd 文件夹的路径` - - -稍等片刻,命令执行完毕后,就可以通过 `http://127.0.0.1:8080` 进行访问 JPress了,此时浏览器会出现 JPress 安装向导,一路 `下一步` 就可以。 - -同时,在 `docker-compose.yml` 所在的同级目录下会出现一个 `templates` 等目录,我们开发自己模板的时候,需要把自己的模板放到`templates` 目录,然后开始开发。 - -**Docker小知识** ->1、通过 Docker Compose 命令启动 JPress 后如何停止? ->答:通过shell进入 docker-compose.yml 所在的目录,然后执行:`docker-compose down` 命令 -> ->2、如何查看 JPress 运行的日志信息? ->答:先通过 `docker ps` 命令查看 JPress 的 container id,然后执行命令:`docker logs -f 查看到的container-id` - - - -## 模板的组成 - -一个完整的模板,文件内容如下: - -``` -mytemplate -├── article.html -├── artlist.html -├── css -│   └── xxx.css -├── img -│   ├── xxx.png -│   ├── xxx.jpg -├── index.html -├── page.html -├── screenshot.png -├── setting.html -└── template.properties -``` - -其中 `index.html` 、 `screenshot.png` 、`template.properties` 是模板的必须文件,一个模板最少由着三个文件组成。 - -- index.html : 网站首页的模板 -- screenshot.png : 后台的模板缩略图 -- template.properties 模板的配置信息 - ->当我们开始开发一个新的模板的时候,可以先用这个三个文件,然后通过 JPress 后台进行安装,看一下效果。 - -模板的配置文件 `template.properties` 内容如下 - -``` -id = cn.jeanstudio.bluelight -title = BlueLight -description = BlueLight是JeanStudio工作室为JPress设计的官网模板 -anthor = jeanStudio -authorWebsite = http://www.jeanstudio.cn -version = 1.0 -versionCode = 1 -updateUrl = -screenshot = screenshot.png -``` - -* id :模板ID,全网唯一,建议用 `域名+名称` 的命名方式 -* title :模板名称 -* description :模板简介 -* anthor :模板作者 -* authorWebsite :模板作者的官网 -* version :版本(不添加默认为1.0.0) -* versionCode :版本号(只能是数字,不填写默认为1) -* screenshot :此模板的缩略图图片(不填写默认为:screenshot.png) - - -## 模板的目录结构 - -- **index.html** :首页模板 -- **error.html** :错误页面模板当系统发生错误的时候,会自动调用此页面进行渲染,也可以扩展为 error_404.html,当发生404错误的时候优先使用此文件,同理可以扩展 error_500.html ,当系统发生500错误的时候调用此文件渲染。 -- **setting.html** :后台的模板设置页面,当次html不存在的时候,用户进入后台的模板设置,会显示此模板不支持设置功能 -- **screenshot.png** :模板缩略图,用于在后台的模板列表里显示的图片 -- **template.properties** :模板信息描述文件 -- **page.html** :页面模块的模板,page.html 可以扩展为 page_aaa.html 、page_bbbb.html ,当模板扩展出 page_xxx.html 的时候,用户在后台发布页面内容的时候,就可以选择使用哪个模板样式进行渲染。例如: page_xxx.html 其中 `xxx` 为样式的名称。 -- **article.html** :文章详情模板, 和page模块一样,article.html 可以扩展出 article_styel1.html、article_style2.html,这样,用户在后台发布文章的时候,可以选择文章样式。(备注:用户中心投稿不能选择样式) -- **artlist.html** :文章列表模板, 和page、article一样,可以通过样式 -- **artsearch.htmll** :文章搜索结果页,用于显示文章的搜索结果。 -- **user_login.html** :用户登录页面,JPress已经内置了登录页面,但是,当模板下有 user_login.html 的时候,就会自动使用模板下的这个页面来渲染 -- **user_register.html** :用注册页面,用法通同 user_login.html -- **user_detail.html** :用户详情页,一般用于显示某个用户的用户信息,用在 http://127.0.0.1/user/用户id 这个页面渲染。 - - - -**备注:** ->所有的模板文件都可以扩展出专门用于渲染手机浏览器的模板。 ->例如:首页的渲染模板是 `index.html` ,如果当前目录下有 `index_h5.html`,那么,当用户通过手机访问网站的时候,JPress 会自动使用 `index_h5.html` 去渲染。 page 和 article、artlist 同理。 - - - - - - -## 模板引擎指令 - -有了以上这些目录结构,我们实际上不用编写任何的标签,就可以制作模板了,只是做出来的模板是静态模板,不能读取后台数据。 - -要读取后台的数据,需要用到模板标签。只有通过在静态的html上,添加 JPress 标签,才能可以读取后台数据。 - -在学习 JPress 模板标签之前,我们需要了解模板引擎的几个基本用法。 - -1、输出功能: - -``` -#(content ??) -``` -2、循环功能: - -``` -#for(item : items) - //...do something -#end -``` -3、判断功能: - -``` -#if(...) - //...do something -#elseif(...) - //...do something -#else - //...do something -#end -``` - -更多的功能和文档,请参考 JPress 模板引擎文档:https://www.jfinal.com/doc/6-4 - - -## 模板标签 - -JPress的模板标签,分为以下三种: - -- 1、全局对象 -- 2、数据指令 - - -#### 全局对象 - -| 名称 | 数据类型 | 标签描述 | -| --- | --- | --- | -| #(WEB_NAME ??) | 字符串 | 网站名称 | -| #(WEB_TITLE ??) | 字符串 | 网站标题 | -| #(WEB_SUBTITLE ??) | 字符串 | 网站副标题 | -| #(WEB_DOMAIN ??) | 字符串 | 网站域名 | -| #(WEB_COPYRIGHT ??) | 字符串 | 网站版权信息 | -| #(SEO_TITLE ??) | 字符串 | 网站SEO标题 | -| #(SEO_KEYWORDS ??) | 字符串 | 网站SEO关键字 | -| #(SEO_DESCRIPTION ??) | 字符串 | 网站SEO描述 | -| MENUS | 数据列表( list ) | 菜单数据 | -| USER | 对象( object ) | 已经登录的用户对象 | -| CSRF_TOKEN | 字符串 | 当进行数据操作的时候必须要传入这个参数 | - -标签描述,标签建议用 `#( 名称 ??)` 的方式来读取数据,而不是用 `#(名称)` 两个问号(??)的意思是如果 后台填写的名称为空格,那么就用 两个问号(??)之后的内容来显示。 - -例如: -`#(WEB_NAME ??)` 表示优先使用 WEB_NAME 来显示,但是当 WEB_NAME 为空的时候,显示空数据(因为两个问好(??)之后的内容为空)。 - -`#(WEB_NAME ?? WEB_TITLE)` 表示优先使用 WEB_NAME 来显示,但是当 WEB_NAME 为空的时候,用 WEB_TITLE(网站标题) 来显示。 - -`#(SEO_TITLE ?? WEB_TITLE +'-'+ WEB_SUBTITLE)` 表示优先使用 SEO_TITLE(SEO标题) 来显示,但是当 SEO_TITLE 为空的时候,用 `WEB_TITLE - WEB_SUBTITLE` 来显示。 - -有了以上知识后,我们的 index.html 首页模板文件可以如下: - -```html - - - - #(SEO_TITLE ?? (WEB_TITLE + '-' + WEB_SUBTITLE)) - - - - -这是首页.... - - -``` - -以上内容都只是针对 `字符串` 这种数据类型进行展示的,全局标签中还有一种数据类型叫 `数据列表( list )`,那么,怎么来显示数据列表呢? - -这个时候`#( 名称 ??)`就不能正常显示了,需要用到一个新的标签: - -```html -#for -... -#end -``` - -`#for ... #end` 标签也叫循环标签,意思是把列表循环显示出来。 - -对于 `MENUS` 这种数据类型为 `数据列表( list )` 的数据,`#for ... #end` 标签使用如下。 - - -```html -#for(menu : MENUS) -

  • #(menu.text ??)
  • -#end -``` - -这样,若我们在后台创建了5个菜单,那么html会输出 5个 `
  • ...
  • ` - -对于以上的菜单显示,还有一个问题就是如何显示二级菜单呢? - -代码如下: - -```html -#for(menu : MENUS) -
  • #(menu.text ??)
  • - #if(menu.hasChild()) -
    - #for(childMenu : menu.getChilds()) -
  • #(menu.text ??)
  • - #end -
    - #end -#end -``` - -以上代码显示了所有菜单的的二级菜单,但是,有些时候我们想在网站的某些位置,显示 **当前菜单** 下的子菜单,如何做呢? - - -代码如下: - -```html -#for(me: MENUS) - #if(me.isActive && me.hasChild()) - - - #end -#end -``` - -在很多模板中,往往需要判断当前用户是否已经登录,用来对模板进行特定的展示。 - -代码如下: - -``` -#if(USER) - #(USER.nickname ??) 欢迎回来,头像:#(USER.avatar ??) - #else - 请登录 - #end +# 模板开发 + +## 目录 + +- 模板开发准备 +- 模板的组成 +- 模板的目录结构 +- 模板的多样式 +- 模板的手机版样式 +- 模板引擎指令 +- 模板标签 +- 模板的安装和卸载 + +## 模板开发准备 + +**1、安装Docker** + +JPress 模板开发准备,主要是准备 docker 环境,Docker 的安装可以参考一下链接: + +* [Mac](https://docs.docker.com/docker-for-mac/install) +* [Windows](https://docs.docker.com/docker-for-windows/install) +* [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu) +* [Debian](https://docs.docker.com/install/linux/docker-ce/debian) +* [CentOS](https://docs.docker.com/install/linux/docker-ce/centos) +* [Fedora](https://docs.docker.com/install/linux/docker-ce/fedora) +* [其他 Linux 发行版](https://docs.docker.com/install/linux/docker-ce/binaries) + +Docker 的安装过程略,一般情况下都是安装比较顺利的,若安装处错自行搜索引擎查询下。 + +**2、通过Docker运行JPress** + +Docker 安装完毕后,下载文件 https://gitee.com/fuhai/jpress/raw/v2.0/docker-compose-for-dev.yml 到本地。(打开此链接,然后右键另存为... 或者按快捷键 `ctrl+s` 保存到本地,mac系统的快捷键是`command+s`) + +下载完毕后,重命名刚刚下载文件 `docker-compose-for-dev.yml` 为 `docker-compose.yml` ,并把 `docker-compose.yml` 放入提前建好的文件夹中。 + +然后通过 shell ( window系统是cmd )进入该文件夹,执行如下命令: + +`docker-compose up -d` + +**Shell小知识** +>如何用命令进入某个文件夹? +>答:进入文件夹的命令是: `cd 文件夹的路径` + + +稍等片刻,命令执行完毕后,就可以通过 `http://127.0.0.1:8080` 进行访问 JPress了,此时浏览器会出现 JPress 安装向导,一路 `下一步` 就可以。 + +同时,在 `docker-compose.yml` 所在的同级目录下会出现一个 `templates` 等目录,我们开发自己模板的时候,需要把自己的模板放到`templates` 目录,然后开始开发。 + +**Docker小知识** +>1、通过 Docker Compose 命令启动 JPress 后如何停止? +>答:通过shell进入 docker-compose.yml 所在的目录,然后执行:`docker-compose down` 命令 +> +>2、如何查看 JPress 运行的日志信息? +>答:先通过 `docker ps` 命令查看 JPress 的 container id,然后执行命令:`docker logs -f 查看到的container-id` + + + +## 模板的组成 + +一个完整的模板,文件内容如下: + +``` +mytemplate +├── article.html +├── artlist.html +├── css +│   └── xxx.css +├── img +│   ├── xxx.png +│   ├── xxx.jpg +├── index.html +├── page.html +├── screenshot.png +├── setting.html +└── template.properties +``` + +其中 `index.html` 、 `screenshot.png` 、`template.properties` 是模板的必须文件,一个模板最少由着三个文件组成。 + +- index.html : 网站首页的模板 +- screenshot.png : 后台的模板缩略图 +- template.properties 模板的配置信息 + +>当我们开始开发一个新的模板的时候,可以先用这个三个文件,然后通过 JPress 后台进行安装,看一下效果。 + +模板的配置文件 `template.properties` 内容如下 + +``` +id = cn.jeanstudio.bluelight +title = BlueLight +description = BlueLight是JeanStudio工作室为JPress设计的官网模板 +anthor = jeanStudio +authorWebsite = http://www.jeanstudio.cn +version = 1.0 +versionCode = 1 +updateUrl = +screenshot = screenshot.png +``` + +* id :模板ID,全网唯一,建议用 `域名+名称` 的命名方式 +* title :模板名称 +* description :模板简介 +* anthor :模板作者 +* authorWebsite :模板作者的官网 +* version :版本(不添加默认为1.0.0) +* versionCode :版本号(只能是数字,不填写默认为1) +* screenshot :此模板的缩略图图片(不填写默认为:screenshot.png) + + +## 模板的目录结构 + +- **index.html** :首页模板 +- **error.html** :错误页面模板当系统发生错误的时候,会自动调用此页面进行渲染,也可以扩展为 error_404.html,当发生404错误的时候优先使用此文件,同理可以扩展 error_500.html ,当系统发生500错误的时候调用此文件渲染。 +- **setting.html** :后台的模板设置页面,当次html不存在的时候,用户进入后台的模板设置,会显示此模板不支持设置功能 +- **screenshot.png** :模板缩略图,用于在后台的模板列表里显示的图片 +- **template.properties** :模板信息描述文件 +- **page.html** :页面模块的模板,page.html 可以扩展为 page_aaa.html 、page_bbbb.html ,当模板扩展出 page_xxx.html 的时候,用户在后台发布页面内容的时候,就可以选择使用哪个模板样式进行渲染。例如: page_xxx.html 其中 `xxx` 为样式的名称。 +- **article.html** :文章详情模板, 和page模块一样,article.html 可以扩展出 article_styel1.html、article_style2.html,这样,用户在后台发布文章的时候,可以选择文章样式。(备注:用户中心投稿不能选择样式) +- **artlist.html** :文章列表模板, 和page、article一样,可以通过样式 +- **artsearch.htmll** :文章搜索结果页,用于显示文章的搜索结果。 +- **user_login.html** :用户登录页面,JPress已经内置了登录页面,但是,当模板下有 user_login.html 的时候,就会自动使用模板下的这个页面来渲染 +- **user_register.html** :用注册页面,用法通同 user_login.html +- **user_detail.html** :用户详情页,一般用于显示某个用户的用户信息,用在 http://127.0.0.1/user/用户id 这个页面渲染。 + + + +**备注:** +>所有的模板文件都可以扩展出专门用于渲染手机浏览器的模板。 +>例如:首页的渲染模板是 `index.html` ,如果当前目录下有 `index_h5.html`,那么,当用户通过手机访问网站的时候,JPress 会自动使用 `index_h5.html` 去渲染。 page 和 article、artlist 同理。 + + + + + + +## 模板引擎指令 + +有了以上这些目录结构,我们实际上不用编写任何的标签,就可以制作模板了,只是做出来的模板是静态模板,不能读取后台数据。 + +要读取后台的数据,需要用到模板标签。只有通过在静态的html上,添加 JPress 标签,才能可以读取后台数据。 + +在学习 JPress 模板标签之前,我们需要了解模板引擎的几个基本用法。 + +1、输出功能: + +``` +#(content ??) +``` +2、循环功能: + +``` +#for(item : items) + //...do something +#end +``` +3、判断功能: + +``` +#if(...) + //...do something +#elseif(...) + //...do something +#else + //...do something +#end +``` + +更多的功能和文档,请参考 JPress 模板引擎文档:https://www.jfinal.com/doc/6-4 + + +## 模板标签 + +JPress的模板标签,分为以下三种: + +- 1、全局对象 +- 2、数据指令 + + +#### 全局对象 + +| 名称 | 数据类型 | 标签描述 | +| --- | --- | --- | +| #(WEB_NAME ??) | 字符串 | 网站名称 | +| #(WEB_TITLE ??) | 字符串 | 网站标题 | +| #(WEB_SUBTITLE ??) | 字符串 | 网站副标题 | +| #(WEB_DOMAIN ??) | 字符串 | 网站域名 | +| #(WEB_COPYRIGHT ??) | 字符串 | 网站版权信息 | +| #(SEO_TITLE ??) | 字符串 | 网站SEO标题 | +| #(SEO_KEYWORDS ??) | 字符串 | 网站SEO关键字 | +| #(SEO_DESCRIPTION ??) | 字符串 | 网站SEO描述 | +| MENUS | 数据列表( list ) | 菜单数据 | +| USER | 对象( object ) | 已经登录的用户对象 | +| CSRF_TOKEN | 字符串 | 当进行数据操作的时候必须要传入这个参数 | + +标签描述,标签建议用 `#( 名称 ??)` 的方式来读取数据,而不是用 `#(名称)` 两个问号(??)的意思是如果 后台填写的名称为空格,那么就用 两个问号(??)之后的内容来显示。 + +例如: +`#(WEB_NAME ??)` 表示优先使用 WEB_NAME 来显示,但是当 WEB_NAME 为空的时候,显示空数据(因为两个问好(??)之后的内容为空)。 + +`#(WEB_NAME ?? WEB_TITLE)` 表示优先使用 WEB_NAME 来显示,但是当 WEB_NAME 为空的时候,用 WEB_TITLE(网站标题) 来显示。 + +`#(SEO_TITLE ?? WEB_TITLE +'-'+ WEB_SUBTITLE)` 表示优先使用 SEO_TITLE(SEO标题) 来显示,但是当 SEO_TITLE 为空的时候,用 `WEB_TITLE - WEB_SUBTITLE` 来显示。 + +有了以上知识后,我们的 index.html 首页模板文件可以如下: + +```html + + + + #(SEO_TITLE ?? (WEB_TITLE + '-' + WEB_SUBTITLE)) + + + + +这是首页.... + + +``` + +以上内容都只是针对 `字符串` 这种数据类型进行展示的,全局标签中还有一种数据类型叫 `数据列表( list )`,那么,怎么来显示数据列表呢? + +这个时候`#( 名称 ??)`就不能正常显示了,需要用到一个新的标签: + +```html +#for +... +#end +``` + +`#for ... #end` 标签也叫循环标签,意思是把列表循环显示出来。 + +对于 `MENUS` 这种数据类型为 `数据列表( list )` 的数据,`#for ... #end` 标签使用如下。 + + +```html +#for(menu : MENUS) +
  • #(menu.text ??)
  • +#end +``` + +这样,若我们在后台创建了5个菜单,那么html会输出 5个 `
  • ...
  • ` + +对于以上的菜单显示,还有一个问题就是如何显示二级菜单呢? + +代码如下: + +```html +#for(menu : MENUS) +
  • #(menu.text ??)
  • + #if(menu.hasChild()) +
    + #for(childMenu : menu.getChilds()) +
  • #(menu.text ??)
  • + #end +
    + #end +#end +``` + +以上代码显示了所有菜单的的二级菜单,但是,有些时候我们想在网站的某些位置,显示 **当前菜单** 下的子菜单,如何做呢? + + +代码如下: + +```html +#for(me: MENUS) + #if(me.isActive && me.hasChild()) + + + #end +#end +``` + +在很多模板中,往往需要判断当前用户是否已经登录,用来对模板进行特定的展示。 + +代码如下: + +``` +#if(USER) + #(USER.nickname ??) 欢迎回来,头像:#(USER.avatar ??) + #else + 请登录 + #end ``` \ No newline at end of file diff --git a/doc/upgrade.md b/doc/upgrade.md index 689a49bdbdcca0216ef73e94267db693965bc558..f2dc0ec40da67eedafcddbcf65976003f022314a 100644 --- a/doc/upgrade.md +++ b/doc/upgrade.md @@ -1,48 +1,48 @@ -# JPress 升级 - -## 目录 -- Tomcat 下升级 JPress -- Docker 下升级 JPress - - -## Tomcat 下升级 JPress - -**第一步** - -下载最新的 war 包到 Linux 上,并解压缩到任意目录,假设解压缩到 `/tmp/jpress` 。 - -**第二步** - -下载 upgrade.sh 到 Linux 上,并给与执行权限。 - -```shell script -wget https://gitee.com/fuhai/jpress/raw/master/upgrade.sh -chmod +x upgrade.sh -``` - -**第三步** - -执行 upgrade.sh,假设要升级的旧的JPress所在的目录为 `/www/tomcat/webapps/jpress`,需要执行 -如下代码 - -```shell script -./upgrade.sh /tmp/jpress /www/tomcat/webapps/jpress -``` - ->upgrade.sh 后面跟两个参数,第一个为新的 war 包解压的目录,第二个参数为需要升级的旧的JPress所在目录。 - -**第四步** - -重启 Tomcat,升级完成。 - - -## Docker 下升级 JPress - -Docker 一般情况是通过 docker-compose.yml 文件来进行部署,升级 JPress 只需要修改 -docker-compose.yml 里的 JPress 的版本号。然后执行如下命令。 - -```shell script -docker-compose down -docker-compose up -d -``` - +# JPress 升级 + +## 目录 +- Tomcat 下升级 JPress +- Docker 下升级 JPress + + +## Tomcat 下升级 JPress + +**第一步** + +下载最新的 war 包到 Linux 上,并解压缩到任意目录,假设解压缩到 `/tmp/jpress` 。 + +**第二步** + +下载 upgrade.sh 到 Linux 上,并给与执行权限。 + +```shell script +wget https://gitee.com/fuhai/jpress/raw/master/upgrade.sh +chmod +x upgrade.sh +``` + +**第三步** + +执行 upgrade.sh,假设要升级的旧的JPress所在的目录为 `/www/tomcat/webapps/jpress`,需要执行 +如下代码 + +```shell script +./upgrade.sh /tmp/jpress /www/tomcat/webapps/jpress +``` + +>upgrade.sh 后面跟两个参数,第一个为新的 war 包解压的目录,第二个参数为需要升级的旧的JPress所在目录。 + +**第四步** + +重启 Tomcat,升级完成。 + + +## Docker 下升级 JPress + +Docker 一般情况是通过 docker-compose.yml 文件来进行部署,升级 JPress 只需要修改 +docker-compose.yml 里的 JPress 的版本号。然后执行如下命令。 + +```shell script +docker-compose down +docker-compose up -d +``` + diff --git a/doc/videos.md b/doc/videos.md index 845fa44ee4ccaa9caf5d4f4f743754dc93a0626e..0d6ede088df8917b5c090dcaab75e31fd2994e2e 100644 --- a/doc/videos.md +++ b/doc/videos.md @@ -1,37 +1,37 @@ -# JPress 视频教程 - -备注,以下 JPress 视频教程中,个别是针对 JPress-School 的 VIP 学员独享的视频教程,若需要加入 JPress-School VIP 社群,请看文章:https://mp.weixin.qq.com/s/GbNv0xaK6jruWqTDJ_Ospw - - -## 视频列表 - -**JPress下载、编译、运行** -https://pan.baidu.com/s/1Pe0KcYcQGalxPnlUNw9rmg - - -**一个小时开发一个论坛** -https://pan.baidu.com/s/1rJ5OMOxUwVz9ylK3oFD3PQ - - -**Press模板开发教程** -https://pan.baidu.com/s/1zSSezfMOfrZxGvs_Sz4Kig 密码:tvzh - - -**JPress与CDN的整合实现** -https://pan.baidu.com/s/10aPgdD1HNZO1qb5ab9YB5w - - -**JPress二次开发视频教程** -https://pan.baidu.com/s/1OGSwWWuLrs1cL4ncJAMLpA - - -**CSRF攻击与JPress优雅的防护机制** -http://www.lezhibo.com/mobile/activity/join?id=b1bce1addc63470ba4711b33f94e8be8 - - -**Http协议详解【直播课程】** -http://www.lezhibo.com/mobile/activity/join?id=9a16e43a2243490ab7bc5be4c70be616 - - -**Jwt与JPress详解** +# JPress 视频教程 + +备注,以下 JPress 视频教程中,个别是针对 JPress-School 的 VIP 学员独享的视频教程,若需要加入 JPress-School VIP 社群,请看文章:https://mp.weixin.qq.com/s/GbNv0xaK6jruWqTDJ_Ospw + + +## 视频列表 + +**JPress下载、编译、运行** +https://pan.baidu.com/s/1Pe0KcYcQGalxPnlUNw9rmg + + +**一个小时开发一个论坛** +https://pan.baidu.com/s/1rJ5OMOxUwVz9ylK3oFD3PQ + + +**Press模板开发教程** +https://pan.baidu.com/s/1zSSezfMOfrZxGvs_Sz4Kig 密码:tvzh + + +**JPress与CDN的整合实现** +https://pan.baidu.com/s/10aPgdD1HNZO1qb5ab9YB5w + + +**JPress二次开发视频教程** +https://pan.baidu.com/s/1OGSwWWuLrs1cL4ncJAMLpA + + +**CSRF攻击与JPress优雅的防护机制** +http://www.lezhibo.com/mobile/activity/join?id=b1bce1addc63470ba4711b33f94e8be8 + + +**Http协议详解【直播课程】** +http://www.lezhibo.com/mobile/activity/join?id=9a16e43a2243490ab7bc5be4c70be616 + + +**Jwt与JPress详解** http://www.lezhibo.com/mobile/activity/join?id=3290428e892e40e084b71680fc73bdb9 \ No newline at end of file diff --git a/doc/vip.md b/doc/vip.md index 83d70ed96f3af80125702866e526658b54abf8ac..7dff0c18a10f76eb6d8f00457b0a6f48ef2c72c7 100644 --- a/doc/vip.md +++ b/doc/vip.md @@ -1,144 +1,144 @@ -# JPressSchool-VIP 会员 - - - - - -JSchool 是海哥为 JPress、Jboot 创办的知识付费社群,使用订阅的付费模式,价格 299元/年。 - - - -## 关于 JPress -JPress 是一个类似 WordPress 的产品,经过两年的发展,JPress 已经成为一个可以和 WordPress 媲美的开源产品,同时,在独特的中国互联网模式下,JPress 完美和微信对接,通过 JPress ,我们可以对微信粉丝进行管理。 - - - -目前,已经有很多基于微信生态的运营插件,包括比如:任务宝、活码工具等产品,得到了大量用户的认可。 - - - -同时,JPress 支持了比如在用户中心、线充值、会员机制、商品下单等商务功能,是企业和个人需求的完美产品。 - - - -## 关于 Jboot -Jboot 是一个基于 JFinal 二次开发的、分布式的开源框架,在 Jboot 开源之初,我所在的企业已经基于其使用在用户量过亿的产品之上。 - - - -又经过这几年的发展,已经被超过 1000+ 企业在使用,包括很多知名的上市公司(包括阿里和华为的某些业务部门)。 - - - -## 关于 海哥 -海哥,JPress 和 Jboot 的作者,目前自主连续创业中...曾在上市公司担任过技术经理、架构师 和 技术总监,曾带领团队完成多个从 0 到 1亿+ 用户量的产品研发,也曾经有过失败的创业经历。 - - - -创业坎坷,但继续前行... - - - -## 关于 JSchool -JSchool 是海哥为 JPress、Jboot 创办的知识付费社群,使用订阅的付费模式,价格 299元/年。 - - - -既是知识付费,目前已经有的课程有: - - - -**一、JPress 相关视频教程(不定时持续更新)** - -- 1.《JPress 二次开发视频教程》 -- 2.《JPress 模板开发教程》 -- 3.《JPress 插件开发教程》 -- 4.《JPress与CDN的整合实现》 -- 5.《CSRF攻击与JPress优雅的防护机制 》 -- 6.《Jwt与JPress详解 》 -- 7.《Http协议详解【直播回放】》 -- 8.《JPress1.x的下载、编译、运行 》 -- 9.《JPress1.x一个小时开发一个论坛 》 -- 10.《...其他会不定时更新》 - - - -**二、《JFinal 4.x 精讲》系列视频教程** - -- 1.《JFinal 快速上手》 -- 2.《JFinal 配置大全》 -- 3.《JFinal 架构》 -- 4.《JFinal Handler》 -- 5.《JFinal Controller》 -- 6.《JFinal Render》 -- 7.《JFinal Inerceptor》 -- 8.《JFinal AOP》 -- 9.《JFinal 数据库操作》 -- 10.《JFinal 模板引擎》 -- 11.《JFinal 插件》 -- 12.《JFinal 总结》 - - - -**三、《亿级用户的数据库架构》视频教程** - -- 1.《课程简介》 -- 2.《拒绝使用Join查询》 -- 3.《主从分组架构的使用场景和原理》 -- 4.《水平切分架构的使用场景和原理》 -- 5.《垂直切分架构的使用场景和原理》 -- 6.《实战:淘宝网用户中心的架构设计》 -- 7.《实战:淘宝网商品搜索的架构设计》 -- 8.《实战:淘宝网订单中心的架构设计》 -- 9.《实战:淘宝网商品交易的架构设计》 -- 10.《课程总结》 - - - -**四、《精通Docker》入门课程视频教程** - -- 1.《课程简介》 -- 2.《Docker的初体验》 -- 3.《Docker基本概念》 -- 4.《Docker基础实战》 -- 5.《从0开始做自己的Docker镜像》 -- 6.《Docker Compose》 -- 7.《Docker与JPress》 -- 8.《课程总结》 - - - -**五、《JPress插件模板技术课程》视频教程** - -- 1.《JPress 简介 及 模板与插件的功能体验》 -- 2.《JPress 模板功能的实现》 -- 3.《JPress 插件功能基本逻辑》 -- 4.《JPress 插件的 Handler 热插拔》 -- 5.《JPress 插件的 Interceptor 热插拔》 -- 6.《JPress 插件的 Controller 热插拔》 -- 7.《JPress 插件的 Model 热插拔 与 数据库表的创建》 -- 8.《JPress 插件的 Directive 热插拔》 -- 9.《JPress 插件的 AOP 自动加载》 -- 10.《JPress 插件的 后台菜单 自动加载》 -- 11.《JPress 插件的 html/css/js 等静态资源加载》 -- 12.《JPress 插件的在线升级与失败回滚功能》 -- 13.《课程总结》 - - - -**其他福利** - -- 1. JSchool 微信专属交流群 -- 2. JPress社区(jpress.io) 有问必答 -- 3. JPress社区 VIP 专属标识 -- 4. JPress元信息插件及其源码(官网售价199) -- 5. 更多关于 Jboot 和 分布式的课程将会陆续更新 - - - - -## 如何付款 -直接扫描下方二维码支付,支付成功后,联系海哥的微信号:fuhai001 , 获取 JSchool 的相关权益。 -![](./images/jschool-pay.png) - - +# JPressSchool-VIP 会员 + + + + + +JSchool 是海哥为 JPress、Jboot 创办的知识付费社群,使用订阅的付费模式,价格 299元/年。 + + + +## 关于 JPress +JPress 是一个类似 WordPress 的产品,经过两年的发展,JPress 已经成为一个可以和 WordPress 媲美的开源产品,同时,在独特的中国互联网模式下,JPress 完美和微信对接,通过 JPress ,我们可以对微信粉丝进行管理。 + + + +目前,已经有很多基于微信生态的运营插件,包括比如:任务宝、活码工具等产品,得到了大量用户的认可。 + + + +同时,JPress 支持了比如在用户中心、线充值、会员机制、商品下单等商务功能,是企业和个人需求的完美产品。 + + + +## 关于 Jboot +Jboot 是一个基于 JFinal 二次开发的、分布式的开源框架,在 Jboot 开源之初,我所在的企业已经基于其使用在用户量过亿的产品之上。 + + + +又经过这几年的发展,已经被超过 1000+ 企业在使用,包括很多知名的上市公司(包括阿里和华为的某些业务部门)。 + + + +## 关于 海哥 +海哥,JPress 和 Jboot 的作者,目前自主连续创业中...曾在上市公司担任过技术经理、架构师 和 技术总监,曾带领团队完成多个从 0 到 1亿+ 用户量的产品研发,也曾经有过失败的创业经历。 + + + +创业坎坷,但继续前行... + + + +## 关于 JSchool +JSchool 是海哥为 JPress、Jboot 创办的知识付费社群,使用订阅的付费模式,价格 299元/年。 + + + +既是知识付费,目前已经有的课程有: + + + +**一、JPress 相关视频教程(不定时持续更新)** + +- 1.《JPress 二次开发视频教程》 +- 2.《JPress 模板开发教程》 +- 3.《JPress 插件开发教程》 +- 4.《JPress与CDN的整合实现》 +- 5.《CSRF攻击与JPress优雅的防护机制 》 +- 6.《Jwt与JPress详解 》 +- 7.《Http协议详解【直播回放】》 +- 8.《JPress1.x的下载、编译、运行 》 +- 9.《JPress1.x一个小时开发一个论坛 》 +- 10.《...其他会不定时更新》 + + + +**二、《JFinal 4.x 精讲》系列视频教程** + +- 1.《JFinal 快速上手》 +- 2.《JFinal 配置大全》 +- 3.《JFinal 架构》 +- 4.《JFinal Handler》 +- 5.《JFinal Controller》 +- 6.《JFinal Render》 +- 7.《JFinal Inerceptor》 +- 8.《JFinal AOP》 +- 9.《JFinal 数据库操作》 +- 10.《JFinal 模板引擎》 +- 11.《JFinal 插件》 +- 12.《JFinal 总结》 + + + +**三、《亿级用户的数据库架构》视频教程** + +- 1.《课程简介》 +- 2.《拒绝使用Join查询》 +- 3.《主从分组架构的使用场景和原理》 +- 4.《水平切分架构的使用场景和原理》 +- 5.《垂直切分架构的使用场景和原理》 +- 6.《实战:淘宝网用户中心的架构设计》 +- 7.《实战:淘宝网商品搜索的架构设计》 +- 8.《实战:淘宝网订单中心的架构设计》 +- 9.《实战:淘宝网商品交易的架构设计》 +- 10.《课程总结》 + + + +**四、《精通Docker》入门课程视频教程** + +- 1.《课程简介》 +- 2.《Docker的初体验》 +- 3.《Docker基本概念》 +- 4.《Docker基础实战》 +- 5.《从0开始做自己的Docker镜像》 +- 6.《Docker Compose》 +- 7.《Docker与JPress》 +- 8.《课程总结》 + + + +**五、《JPress插件模板技术课程》视频教程** + +- 1.《JPress 简介 及 模板与插件的功能体验》 +- 2.《JPress 模板功能的实现》 +- 3.《JPress 插件功能基本逻辑》 +- 4.《JPress 插件的 Handler 热插拔》 +- 5.《JPress 插件的 Interceptor 热插拔》 +- 6.《JPress 插件的 Controller 热插拔》 +- 7.《JPress 插件的 Model 热插拔 与 数据库表的创建》 +- 8.《JPress 插件的 Directive 热插拔》 +- 9.《JPress 插件的 AOP 自动加载》 +- 10.《JPress 插件的 后台菜单 自动加载》 +- 11.《JPress 插件的 html/css/js 等静态资源加载》 +- 12.《JPress 插件的在线升级与失败回滚功能》 +- 13.《课程总结》 + + + +**其他福利** + +- 1. JSchool 微信专属交流群 +- 2. JPress社区(jpress.io) 有问必答 +- 3. JPress社区 VIP 专属标识 +- 4. JPress元信息插件及其源码(官网售价199) +- 5. 更多关于 Jboot 和 分布式的课程将会陆续更新 + + + + +## 如何付款 +直接扫描下方二维码支付,支付成功后,联系海哥的微信号:fuhai001 , 获取 JSchool 的相关权益。 +![](./images/jschool-pay.png) + + diff --git a/doc/wechat_dev.md b/doc/wechat_dev.md index 56360a1919f0dbd53aad0786fe956a43fdb15f26..4b3b28f0469a6706a988ca8f937791bf27d12ab6 100644 --- a/doc/wechat_dev.md +++ b/doc/wechat_dev.md @@ -1,95 +1,95 @@ -# JPress 微信插件开发 - -## 目录 - -- 微信公众号配置 -- 开发JPress微信运营插件 -- JPress微信运营插件的 Hello World -- 测试JPress微信运营插件 - -## 微信公众号配置 - -在开发 JPress 微信运营插件之前,建议(但不是必须)先做好微信公众号的配置,微信公众号配置请参考《JPress产品手册之微信公众号配置》章节。 - -同时,JPress 微信运营插件开发完毕后,必须做好微信公众号配置后,才能进行插件测试。 - -## 开发JPress微信运营插件 - -在 jpress 体系中,值需要编写任意名称的 Java 类,实现 `WechatAddon` 接口即可 ,参考如下实例: - -```java -public class HelloWechatAddon implements WechatAddon { - - @Override - public boolean onMatchingMessage(InMsg inMsg, - MsgController msgController) { - - return false; - } - - @Override - public boolean onRenderMessage(InMsg inMsg, - MsgController msgController) { - - return true; - } -} -``` -**说明:** - -* 1、在任意maven module下,编写任意名称的类,实现WechatAddon接口。JPress 会自动扫描到该类,并添加到 JPress 的管理体系里去。 -* 2、复写方法`onMatchingMessage`和`onRenderMessage`。 - * onMatchingMessage :用来匹配是否是本插件要处理的消息 - * onRenderMessage :用来返回给微信客户端一个消息 - -* 3、添加 `@WechatAddonConfig` 注解的配置,用来给这个插件添加描述。 - - -## JPress微信运营插件的 Hello World -以下代码是完整的 hello world 例子,当用户在微信客户端(手机端),给公众号输入 `hello` 的时候,服务器给微信返回 `world` 字符串: - -```java -@WechatAddonConfig( - id = "ip.press.helloaddon", //这个插件的ID - title = "Hello World",//这个插件的标题,用于在后台显示 - description = "这是一个 Hello World 微信插件,方便开发参考。用户输入 hello,返回 world", //这个插件的描述 - author = "海哥" //这个插件的作者 -) -public class HelloWechatAddon implements WechatAddon { - - @Override - public boolean onMatchingMessage(InMsg inMsg, MsgController msgController) { - - //当用户给公众号发送的不是文本消息的时候 - //返回 false 不由本插件处理 - if (!(inMsg instanceof InTextMsg)) { - return false; - } - - InTextMsg inTextMsg = (InTextMsg) inMsg; - String content = inTextMsg.getContent(); - - //当用户输入的内容不是 hello 的时候 - //返回false,不由本插件处理 - return content != null && content.equalsIgnoreCase("hello"); - } - - - @Override - public boolean onRenderMessage(InMsg inMsg, MsgController msgController) { - - //创建一个新的文本消息 - //通过 msgController 进行渲染返回给用户 - OutTextMsg outTextMsg = new OutTextMsg(inMsg); - outTextMsg.setContent("world"); - msgController.render(outTextMsg); - - //返回 true,表示本插件已经成功处理该消息 - //若返回false,表示本插件处理消息失败,将会交给系统或者其他插件去处理 - return true; - } -} -``` -完整代码可以看这里:https://gitee.com/fuhai/jpress/blob/master/jpress-web/src/main/java/io/jpress/web/wechat/HelloWechatAddon.java - +# JPress 微信插件开发 + +## 目录 + +- 微信公众号配置 +- 开发JPress微信运营插件 +- JPress微信运营插件的 Hello World +- 测试JPress微信运营插件 + +## 微信公众号配置 + +在开发 JPress 微信运营插件之前,建议(但不是必须)先做好微信公众号的配置,微信公众号配置请参考《JPress产品手册之微信公众号配置》章节。 + +同时,JPress 微信运营插件开发完毕后,必须做好微信公众号配置后,才能进行插件测试。 + +## 开发JPress微信运营插件 + +在 jpress 体系中,值需要编写任意名称的 Java 类,实现 `WechatAddon` 接口即可 ,参考如下实例: + +```java +public class HelloWechatAddon implements WechatAddon { + + @Override + public boolean onMatchingMessage(InMsg inMsg, + MsgController msgController) { + + return false; + } + + @Override + public boolean onRenderMessage(InMsg inMsg, + MsgController msgController) { + + return true; + } +} +``` +**说明:** + +* 1、在任意maven module下,编写任意名称的类,实现WechatAddon接口。JPress 会自动扫描到该类,并添加到 JPress 的管理体系里去。 +* 2、复写方法`onMatchingMessage`和`onRenderMessage`。 + * onMatchingMessage :用来匹配是否是本插件要处理的消息 + * onRenderMessage :用来返回给微信客户端一个消息 + +* 3、添加 `@WechatAddonConfig` 注解的配置,用来给这个插件添加描述。 + + +## JPress微信运营插件的 Hello World +以下代码是完整的 hello world 例子,当用户在微信客户端(手机端),给公众号输入 `hello` 的时候,服务器给微信返回 `world` 字符串: + +```java +@WechatAddonConfig( + id = "ip.press.helloaddon", //这个插件的ID + title = "Hello World",//这个插件的标题,用于在后台显示 + description = "这是一个 Hello World 微信插件,方便开发参考。用户输入 hello,返回 world", //这个插件的描述 + author = "海哥" //这个插件的作者 +) +public class HelloWechatAddon implements WechatAddon { + + @Override + public boolean onMatchingMessage(InMsg inMsg, MsgController msgController) { + + //当用户给公众号发送的不是文本消息的时候 + //返回 false 不由本插件处理 + if (!(inMsg instanceof InTextMsg)) { + return false; + } + + InTextMsg inTextMsg = (InTextMsg) inMsg; + String content = inTextMsg.getContent(); + + //当用户输入的内容不是 hello 的时候 + //返回false,不由本插件处理 + return content != null && content.equalsIgnoreCase("hello"); + } + + + @Override + public boolean onRenderMessage(InMsg inMsg, MsgController msgController) { + + //创建一个新的文本消息 + //通过 msgController 进行渲染返回给用户 + OutTextMsg outTextMsg = new OutTextMsg(inMsg); + outTextMsg.setContent("world"); + msgController.render(outTextMsg); + + //返回 true,表示本插件已经成功处理该消息 + //若返回false,表示本插件处理消息失败,将会交给系统或者其他插件去处理 + return true; + } +} +``` +完整代码可以看这里:https://gitee.com/fuhai/jpress/blob/master/jpress-web/src/main/java/io/jpress/web/wechat/HelloWechatAddon.java + ## 测试JPress微信运营插件 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a173b5a9e8b67db16403ca533d2af143ce39c0f4..41975fcb6f7cc11e5a88455e24b17b4b7b43f1f5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,38 +1,38 @@ -version: '3.1' - -services: - - db: - image: mysql:5.7 - command: --default-authentication-plugin=mysql_native_password - restart: always - environment: - MYSQL_ROOT_PASSWORD: jpress - MYSQL_DATABASE: jpress - MYSQL_USER: jpress - MYSQL_PASSWORD: jpress - volumes: - - "./docker_volumes/mysql:/var/lib/mysql" - - jpress: - depends_on: - - db - links: - - db - image: fuhai/jpress:v3.2.3 - ports: - - "8080:8080" - restart: always - environment: - TZ: Asia/Shanghai - JPRESS_DB_HOST: db - JPRESS_DB_PORT: 3306 - JPRESS_DB_NAME: jpress - JPRESS_DB_USER: jpress - JPRESS_DB_PASSWORD: jpress - volumes: - - "./docker_volumes/webapp/attachment:/opt/jpress/webapp/attachment" - - "./docker_volumes/webapp/addons:/opt/jpress/webapp/addons" - - "./docker_volumes/webapp/WEB-INF/addons:/opt/jpress/webapp/WEB-INF/addons" - - "./docker_volumes/webapp/wp-content:/opt/jpress/webapp/wp-content" +version: '3.1' + +services: + + db: + image: mysql:5.7 + command: --default-authentication-plugin=mysql_native_password + restart: always + environment: + MYSQL_ROOT_PASSWORD: jpress + MYSQL_DATABASE: jpress + MYSQL_USER: jpress + MYSQL_PASSWORD: jpress + volumes: + - "./docker_volumes/mysql:/var/lib/mysql" + + jpress: + depends_on: + - db + links: + - db + image: fuhai/jpress:v3.2.3 + ports: + - "8080:8080" + restart: always + environment: + TZ: Asia/Shanghai + JPRESS_DB_HOST: db + JPRESS_DB_PORT: 3306 + JPRESS_DB_NAME: jpress + JPRESS_DB_USER: jpress + JPRESS_DB_PASSWORD: jpress + volumes: + - "./docker_volumes/webapp/attachment:/opt/jpress/webapp/attachment" + - "./docker_volumes/webapp/addons:/opt/jpress/webapp/addons" + - "./docker_volumes/webapp/WEB-INF/addons:/opt/jpress/webapp/WEB-INF/addons" + - "./docker_volumes/webapp/wp-content:/opt/jpress/webapp/wp-content" - "./docker_volumes/webapp/templates/dockers:/opt/jpress/webapp/templates/dockers" \ No newline at end of file diff --git a/docker/Dockerfile.base b/docker/Dockerfile.base index 2248d643e3b257a6da144f26dee042e75203a1a5..5a25547c52f4ca5b66657c5d368c5ef734d901da 100644 --- a/docker/Dockerfile.base +++ b/docker/Dockerfile.base @@ -1,10 +1,10 @@ -FROM openjdk:8-jdk-alpine -LABEL maintainer="Michael Yang" - -ENV TZ=Asia/Shanghai -RUN ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime && \ - echo ${TZ} > /etc/timezone - -COPY ./files/wqy-zenhei.ttc /usr/lib/jvm/java-1.8-openjdk/jre/lib/fonts/wqy-zenhei.ttc - +FROM openjdk:8-jdk-alpine +LABEL maintainer="Michael Yang" + +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime && \ + echo ${TZ} > /etc/timezone + +COPY ./files/wqy-zenhei.ttc /usr/lib/jvm/java-1.8-openjdk/jre/lib/fonts/wqy-zenhei.ttc + RUN apk add --no-cache curl tar bash procps ttf-dejavu \ No newline at end of file diff --git a/docker/docker-compose-dev.yml b/docker/docker-compose-dev.yml index 6be0b27d9d86947814a37f93e2dddb6fdcca293d..8692c2946a2a143320cdab9f6267ff1cb586fd8b 100644 --- a/docker/docker-compose-dev.yml +++ b/docker/docker-compose-dev.yml @@ -1,40 +1,40 @@ -version: '3.1' - -services: - - db: - image: mysql:5.6 - command: --default-authentication-plugin=mysql_native_password - restart: always - environment: - MYSQL_ROOT_PASSWORD: jpress - MYSQL_DATABASE: jpress - MYSQL_USER: jpress - MYSQL_PASSWORD: jpress - volumes: - - "./docker_volumes/mysql:/var/lib/mysql" - - jpress: - depends_on: - - db - links: - - db - image: fuhai/jpress:v2.0.8 - ports: - - "8080:8080" - restart: always - environment: - TZ: Asia/Shanghai - JPRESS_DB_HOST: db - JPRESS_DB_PORT: 3306 - JPRESS_DB_NAME: jpress - JPRESS_DB_USER: jpress - JPRESS_DB_PASSWORD: jpress - JBOOT_APP_MODE: dev - UNDERTOW_HOTSWAPCLASSPREFIX: io.jpress - volumes: - - "./docker_volumes/webapp/attachment:/opt/jpress/webapp/attachment" - - "./docker_volumes/webapp/addons:/opt/jpress/webapp/addons" - - "./docker_volumes/webapp/WEB-INF/addons:/opt/jpress/webapp/WEB-INF/addons" - - "./docker_volumes/webapp/wp-content:/opt/jpress/webapp/wp-content" +version: '3.1' + +services: + + db: + image: mysql:5.6 + command: --default-authentication-plugin=mysql_native_password + restart: always + environment: + MYSQL_ROOT_PASSWORD: jpress + MYSQL_DATABASE: jpress + MYSQL_USER: jpress + MYSQL_PASSWORD: jpress + volumes: + - "./docker_volumes/mysql:/var/lib/mysql" + + jpress: + depends_on: + - db + links: + - db + image: fuhai/jpress:v2.0.8 + ports: + - "8080:8080" + restart: always + environment: + TZ: Asia/Shanghai + JPRESS_DB_HOST: db + JPRESS_DB_PORT: 3306 + JPRESS_DB_NAME: jpress + JPRESS_DB_USER: jpress + JPRESS_DB_PASSWORD: jpress + JBOOT_APP_MODE: dev + UNDERTOW_HOTSWAPCLASSPREFIX: io.jpress + volumes: + - "./docker_volumes/webapp/attachment:/opt/jpress/webapp/attachment" + - "./docker_volumes/webapp/addons:/opt/jpress/webapp/addons" + - "./docker_volumes/webapp/WEB-INF/addons:/opt/jpress/webapp/WEB-INF/addons" + - "./docker_volumes/webapp/wp-content:/opt/jpress/webapp/wp-content" - "./docker_volumes/webapp/templates/dockers:/opt/jpress/webapp/templates/dockers" \ No newline at end of file diff --git a/docker/docker-compose-nginx.yml b/docker/docker-compose-nginx.yml index 61abc30c912a8f696d5f9d4231f5d6f044c8b7fd..197199636569ccb99be2aa89abd0bbf007048d07 100644 --- a/docker/docker-compose-nginx.yml +++ b/docker/docker-compose-nginx.yml @@ -1,53 +1,53 @@ -version: '3.1' - -services: - - db: - image: mysql:5.6 - command: --default-authentication-plugin=mysql_native_password - restart: always - environment: - MYSQL_ROOT_PASSWORD: jpress - MYSQL_DATABASE: jpress - MYSQL_USER: jpress - MYSQL_PASSWORD: jpress - volumes: - - "./docker_volumes/mysql:/var/lib/mysql" - - jpress: - depends_on: - - db - links: - - db - image: fuhai/jpress:v2.0.8 - restart: always - environment: - TZ: Asia/Shanghai - JPRESS_DB_HOST: db - JPRESS_DB_PORT: 3306 - JPRESS_DB_NAME: jpress - JPRESS_DB_USER: jpress - JPRESS_DB_PASSWORD: jpress - volumes: - - "./docker_volumes/webapp/attachment:/opt/jpress/webapp/attachment" - - "./docker_volumes/webapp/addons:/opt/jpress/webapp/addons" - - "./docker_volumes/webapp/WEB-INF/addons:/opt/jpress/webapp/WEB-INF/addons" - - "./docker_volumes/webapp/wp-content:/opt/jpress/webapp/wp-content" - - "./docker_volumes/webapp/templates/dockers:/opt/jpress/webapp/templates/dockers" - - nginx: - depends_on: - - jpress - links: - - jpress - image: nginx:1.17 - volumes: - - "./nginx/nginx.conf:/etc/nginx/nginx.conf" - - "./nginx/cert:/etc/nginx/cert" - - "./docker_volumes/webapp/attachment:/etc/nginx/statics/attachment" - - "./docker_volumes/webapp/addons:/etc/nginx/statics/addons" - - "./docker_volumes/webapp/templates:/etc/nginx/statics/templates" - ports: - - "80:80" - restart: always - +version: '3.1' + +services: + + db: + image: mysql:5.6 + command: --default-authentication-plugin=mysql_native_password + restart: always + environment: + MYSQL_ROOT_PASSWORD: jpress + MYSQL_DATABASE: jpress + MYSQL_USER: jpress + MYSQL_PASSWORD: jpress + volumes: + - "./docker_volumes/mysql:/var/lib/mysql" + + jpress: + depends_on: + - db + links: + - db + image: fuhai/jpress:v2.0.8 + restart: always + environment: + TZ: Asia/Shanghai + JPRESS_DB_HOST: db + JPRESS_DB_PORT: 3306 + JPRESS_DB_NAME: jpress + JPRESS_DB_USER: jpress + JPRESS_DB_PASSWORD: jpress + volumes: + - "./docker_volumes/webapp/attachment:/opt/jpress/webapp/attachment" + - "./docker_volumes/webapp/addons:/opt/jpress/webapp/addons" + - "./docker_volumes/webapp/WEB-INF/addons:/opt/jpress/webapp/WEB-INF/addons" + - "./docker_volumes/webapp/wp-content:/opt/jpress/webapp/wp-content" + - "./docker_volumes/webapp/templates/dockers:/opt/jpress/webapp/templates/dockers" + + nginx: + depends_on: + - jpress + links: + - jpress + image: nginx:1.17 + volumes: + - "./nginx/nginx.conf:/etc/nginx/nginx.conf" + - "./nginx/cert:/etc/nginx/cert" + - "./docker_volumes/webapp/attachment:/etc/nginx/statics/attachment" + - "./docker_volumes/webapp/addons:/etc/nginx/statics/addons" + - "./docker_volumes/webapp/templates:/etc/nginx/statics/templates" + ports: + - "80:80" + restart: always + diff --git a/docker/files/jboot.properties b/docker/files/jboot.properties index 71d9f11582cdb21b1aae6d794904fd9e02df73d4..08f0ab5b01210bcefb5736d29e794b8e815e7d37 100644 --- a/docker/files/jboot.properties +++ b/docker/files/jboot.properties @@ -1,4 +1,4 @@ -jboot.app.mode=product -undertow.host=0.0.0.0 -undertow.port=8080 +jboot.app.mode=product +undertow.host=0.0.0.0 +undertow.port=8080 undertow.devMode=false \ No newline at end of file diff --git a/docker/files/jpress.sh b/docker/files/jpress.sh index 1c73f594f5695756b84e85f1f7f5cae8809b3104..ecffdbb050a6bddf97228709ef620e45bd1f56d3 100644 --- a/docker/files/jpress.sh +++ b/docker/files/jpress.sh @@ -1,46 +1,46 @@ -#!/bin/bash -# ---------------------------------------------------------------------- -# name: jpress.sh -# version: 1.0 -# description: JPress 控制脚本 -# author: yangfuhai -# email: fuhai999@gmail.com -# use : ./jpress.sh {start, stop, restart} -# ---------------------------------------------------------------------- - -# 启动入口类,该脚本文件用于别的项目时要改这里 -MAIN_CLASS=io.jboot.app.JbootApplication -COMMAND="$1" - -if [[ "$COMMAND" != "start" ]] && [[ "$COMMAND" != "stop" ]] && [[ "$COMMAND" != "restart" ]]; then - echo "./jpress.sh {start, stop, restart}" - exit 0 -fi - -# Java 命令行参数,根据需要开启下面的配置,改成自己需要的,注意等号前后不能有空格 -# JAVA_OPTS="-Xms256m -Xmx1024m -Dundertow.port=80 -Dundertow.host=0.0.0.0" -# JAVA_OPTS="-Dundertow.port=8080 -Dundertow.host=0.0.0.0" - -# 生成 class path 值 -APP_BASE_PATH=$(cd `dirname $0`; pwd) -CP=${APP_BASE_PATH}/config:${APP_BASE_PATH}/lib/* - -function start() -{ - java -Djava.awt.headless=true -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS} -} - -function stop() -{ - kill `pgrep -f ${MAIN_CLASS}` 2>/dev/null - -} - -if [[ "$COMMAND" == "start" ]]; then - start -elif [[ "$COMMAND" == "stop" ]]; then - stop -else - stop - start -fi +#!/bin/bash +# ---------------------------------------------------------------------- +# name: jpress.sh +# version: 1.0 +# description: JPress 控制脚本 +# author: yangfuhai +# email: fuhai999@gmail.com +# use : ./jpress.sh {start, stop, restart} +# ---------------------------------------------------------------------- + +# 启动入口类,该脚本文件用于别的项目时要改这里 +MAIN_CLASS=io.jboot.app.JbootApplication +COMMAND="$1" + +if [[ "$COMMAND" != "start" ]] && [[ "$COMMAND" != "stop" ]] && [[ "$COMMAND" != "restart" ]]; then + echo "./jpress.sh {start, stop, restart}" + exit 0 +fi + +# Java 命令行参数,根据需要开启下面的配置,改成自己需要的,注意等号前后不能有空格 +# JAVA_OPTS="-Xms256m -Xmx1024m -Dundertow.port=80 -Dundertow.host=0.0.0.0" +# JAVA_OPTS="-Dundertow.port=8080 -Dundertow.host=0.0.0.0" + +# 生成 class path 值 +APP_BASE_PATH=$(cd `dirname $0`; pwd) +CP=${APP_BASE_PATH}/config:${APP_BASE_PATH}/lib/* + +function start() +{ + java -Djava.awt.headless=true -Xverify:none ${JAVA_OPTS} -cp ${CP} ${MAIN_CLASS} +} + +function stop() +{ + kill `pgrep -f ${MAIN_CLASS}` 2>/dev/null + +} + +if [[ "$COMMAND" == "start" ]]; then + start +elif [[ "$COMMAND" == "stop" ]]; then + stop +else + stop + start +fi diff --git a/docker/files/settings.xml b/docker/files/settings.xml index 3e7a8fd8d077eec380a8b608763e95d22c6491d9..d78170ea461bc4fc6104e47c9f353264eb796f1a 100644 --- a/docker/files/settings.xml +++ b/docker/files/settings.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - alimaven - aliyun maven - http://maven.aliyun.com/nexus/content/groups/public/ - central - - - - - - - + + + + + + + + + + + + + + alimaven + aliyun maven + http://maven.aliyun.com/nexus/content/groups/public/ + central + + + + + + + diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf index 1af6359ed3e6deec5849df8b254eff224b03f2ca..ec6dc8796814bff13a5a5a773991ae099edbea6b 100644 --- a/docker/nginx/nginx.conf +++ b/docker/nginx/nginx.conf @@ -1,76 +1,76 @@ -user root root; -worker_processes 4; -#pid logs/nginx.pid; -worker_rlimit_nofile 204800; - -events { - use epoll; - worker_connections 204800; -} - -http { - include mime.types; - default_type application/octet-stream; - charset utf-8; - server_names_hash_bucket_size 128; - client_header_buffer_size 2k; - large_client_header_buffers 4 4k; - client_max_body_size 8m; - sendfile on; - tcp_nopush on; - keepalive_timeout 60; - open_file_cache max=204800 inactive=20s; - open_file_cache_min_uses 1; - open_file_cache_valid 30s; - tcp_nodelay on; - gzip on; - gzip_min_length 1k; - gzip_buffers 4 16k; - gzip_http_version 1.0; - gzip_comp_level 2; - gzip_types text/plain application/x-javascript text/css application/xml; - gzip_vary on; - server_tokens off; - - upstream backend { - server jpress:8080 max_fails=1 fail_timeout=60s; - } - -# server { -# listen 443; -# server_name jpress; -# ssl on; -# ssl_certificate ./cert/server.crt; -# ssl_certificate_key ./cert/server.key; -# ssl_session_timeout 5m; -# ssl_protocols SSLv2 SSLv3 TLSv1; -# ssl_ciphers HIGH:!aNULL:!MD5; -# ssl_prefer_server_ciphers on; -# location ~* .*\.(html|gif|jpg|jpeg|png|bmp|ico|rar|css|js|zip|java|jar|txt|flv|swf|mid|doc|ppt|xls|pdf|txt|mp3|wma|mp4)$ { -# root /etc/nginx/static; -# } -# location / { -# proxy_pass http://xxx.xxx.com; -# proxy_set_header Host $host; -# proxy_set_header X-Real-IP $remote_addr; -# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -# } -# } - - server { - listen 80; - server_name localhost; - ssl off; - location ~* .*\.(gif|jpg|jpeg|png|bmp|ico|rar|css|js|zip|java|jar|txt|flv|swf|mid|doc|ppt|xls|pdf|txt|mp3|wma|mp4)$ { - root /etc/nginx/statics; - expires 30d; - } - location / { - proxy_pass http://backend; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - } - -} +user root root; +worker_processes 4; +#pid logs/nginx.pid; +worker_rlimit_nofile 204800; + +events { + use epoll; + worker_connections 204800; +} + +http { + include mime.types; + default_type application/octet-stream; + charset utf-8; + server_names_hash_bucket_size 128; + client_header_buffer_size 2k; + large_client_header_buffers 4 4k; + client_max_body_size 8m; + sendfile on; + tcp_nopush on; + keepalive_timeout 60; + open_file_cache max=204800 inactive=20s; + open_file_cache_min_uses 1; + open_file_cache_valid 30s; + tcp_nodelay on; + gzip on; + gzip_min_length 1k; + gzip_buffers 4 16k; + gzip_http_version 1.0; + gzip_comp_level 2; + gzip_types text/plain application/x-javascript text/css application/xml; + gzip_vary on; + server_tokens off; + + upstream backend { + server jpress:8080 max_fails=1 fail_timeout=60s; + } + +# server { +# listen 443; +# server_name jpress; +# ssl on; +# ssl_certificate ./cert/server.crt; +# ssl_certificate_key ./cert/server.key; +# ssl_session_timeout 5m; +# ssl_protocols SSLv2 SSLv3 TLSv1; +# ssl_ciphers HIGH:!aNULL:!MD5; +# ssl_prefer_server_ciphers on; +# location ~* .*\.(html|gif|jpg|jpeg|png|bmp|ico|rar|css|js|zip|java|jar|txt|flv|swf|mid|doc|ppt|xls|pdf|txt|mp3|wma|mp4)$ { +# root /etc/nginx/static; +# } +# location / { +# proxy_pass http://xxx.xxx.com; +# proxy_set_header Host $host; +# proxy_set_header X-Real-IP $remote_addr; +# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +# } +# } + + server { + listen 80; + server_name localhost; + ssl off; + location ~* .*\.(gif|jpg|jpeg|png|bmp|ico|rar|css|js|zip|java|jar|txt|flv|swf|mid|doc|ppt|xls|pdf|txt|mp3|wma|mp4)$ { + root /etc/nginx/statics; + expires 30d; + } + location / { + proxy_pass http://backend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } + +} diff --git a/docker/push-base.sh b/docker/push-base.sh index 0bb1cd30542a25099c4d5bd05f7664415fb378af..5b4d25ad9a50565bf4c431fffec8d440c34c18e4 100755 --- a/docker/push-base.sh +++ b/docker/push-base.sh @@ -1,2 +1,2 @@ -docker login +docker login docker push fuhai/jpress-base:v1.4 \ No newline at end of file diff --git a/install.sh b/install.sh index ed10c2cfb4a017cc3330fdcc1c95d2263031980e..90b4c6f83bff34cf61f6aa4b54bc7f7c00f1496d 100755 --- a/install.sh +++ b/install.sh @@ -1,72 +1,72 @@ -#!/bin/bash -# ---------------------------------------------------------------------- -# author: yangfuhai -# email: fuhai999@gmail.com -# use : wget https://gitee.com/fuhai/jpress/raw/master/install.sh && bash install.sh -# ---------------------------------------------------------------------- - - -# 安装docker -if ! [ -x "$(command -v docker)" ]; then - echo '检测到 Docker 尚未安装,正在试图安装 Docker ...' - - if [ -x "$(command -v yum)" ]; then - sudo yum install -y python3-pip yum-utils device-mapper-persistent-data lvm2 - sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo - yum list docker-ce --showduplicates | sort -r - sudo yum install docker-ce - else - sudo apt-get update - sudo dpkg --configure -a - sudo apt-get install python3-pip apt-transport-https ca-certificates curl software-properties-common - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" - sudo apt-get update - sudo apt-get install docker-ce - fi - - # 启动docker和开机自启动 - sudo systemctl start docker - sudo systemctl enable docker -fi - - - # 安装docker-compose -if ! [ -x "$(command -v docker-compose)" ]; then - echo '检测到 Docker-Compose 尚未安装,正在试图安装 Docker-Compose ...' - if ! [ -x "$(command -v pip3)" ]; then - curl -L https://github.com/docker/compose/releases/download/1.25.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose - chmod +x /usr/local/bin/docker-compose - else - pip3 install --upgrade pip - pip3 install docker-compose - fi -fi - - - # 开始安装 jpress -if [ -x "$(command -v docker)" -a -x "$(command -v docker-compose)" ]; then - docker version - docker-compose -version - - # 安装jpress - if [ ! -f "docker-compose.yml" ];then - wget https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml - fi - - docker-compose up -d - -else - - if ! [ -x "$(command -v docker)" ]; then - echo 'Docker 安装失败,请检测您当前的环境(或网络)是否正常。' - fi - - - if ! [ -x "$(command -v docker-compose)" ]; then - echo 'Docker-Compose 安装失败,请检测您当前的环境(或网络)是否正常。' - fi - -fi - +#!/bin/bash +# ---------------------------------------------------------------------- +# author: yangfuhai +# email: fuhai999@gmail.com +# use : wget https://gitee.com/fuhai/jpress/raw/master/install.sh && bash install.sh +# ---------------------------------------------------------------------- + + +# 安装docker +if ! [ -x "$(command -v docker)" ]; then + echo '检测到 Docker 尚未安装,正在试图安装 Docker ...' + + if [ -x "$(command -v yum)" ]; then + sudo yum install -y python3-pip yum-utils device-mapper-persistent-data lvm2 + sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo + yum list docker-ce --showduplicates | sort -r + sudo yum install docker-ce + else + sudo apt-get update + sudo dpkg --configure -a + sudo apt-get install python3-pip apt-transport-https ca-certificates curl software-properties-common + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - + sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" + sudo apt-get update + sudo apt-get install docker-ce + fi + + # 启动docker和开机自启动 + sudo systemctl start docker + sudo systemctl enable docker +fi + + + # 安装docker-compose +if ! [ -x "$(command -v docker-compose)" ]; then + echo '检测到 Docker-Compose 尚未安装,正在试图安装 Docker-Compose ...' + if ! [ -x "$(command -v pip3)" ]; then + curl -L https://github.com/docker/compose/releases/download/1.25.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose + else + pip3 install --upgrade pip + pip3 install docker-compose + fi +fi + + + # 开始安装 jpress +if [ -x "$(command -v docker)" -a -x "$(command -v docker-compose)" ]; then + docker version + docker-compose -version + + # 安装jpress + if [ ! -f "docker-compose.yml" ];then + wget https://gitee.com/fuhai/jpress/raw/master/docker-compose.yml + fi + + docker-compose up -d + +else + + if ! [ -x "$(command -v docker)" ]; then + echo 'Docker 安装失败,请检测您当前的环境(或网络)是否正常。' + fi + + + if ! [ -x "$(command -v docker-compose)" ]; then + echo 'Docker-Compose 安装失败,请检测您当前的环境(或网络)是否正常。' + fi + +fi + rm -f install.sh \ No newline at end of file diff --git a/jpress-addons/jpress-addon-categoryTag/pom.xml b/jpress-addons/jpress-addon-categoryTag/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..8d049915f771478a09ccc540786a94e7a773fcdc --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + io.jpress + jpress-addons + 3.0 + + jpress-addon-menuTag + jar + jpress-addon-menuTag + http://maven.apache.org + + + io.jpress + jpress-core + + + + + + + + + src/main/resources + + **/*.* + + false + + + + src/main/webapp + + **/*.* + + false + + + + + diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddon.java b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddon.java new file mode 100644 index 0000000000000000000000000000000000000000..6fa4bb073cfa55f84d3b33c52de3aff12be3fe1c --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddon.java @@ -0,0 +1,63 @@ +package org.jpress.addon.menutag; + +import io.jpress.core.addon.Addon; +import io.jpress.core.addon.AddonInfo; + +/** + * 这是一个 JPress 插件的 hello world 项目,没有具体的功能。 + * + * 其存在的目的是为了帮助开发者,通过 hello world ,了解如何开发一个 JPress 插件 + * + */ +public class MenuTagAddon implements Addon { + + @Override + public void onInstall(AddonInfo addonInfo) { + + /** + * 在 onInstall ,我们一般需要 创建自己的数据表 + * + * onInstall 方法只会执行一次,执行完毕之后不会再执行,除非是用户卸载插件再次安装 + */ + //System.out.println("HelloWorldAddon onInstall"); + + } + + @Override + public void onUninstall(AddonInfo addonInfo) { + + /** + * 在 onUninstall 中,我们一般需要去删除自己在 onInstall 中创建的表 或者 其他资源文件 + * 这个方法是用户在 Jpress 后台卸载插件的时候回触发。 + */ + + //System.out.println("HelloWorldAddon onUninstall"); + } + + @Override + public void onStart(AddonInfo addonInfo) { + + /** + * 在 onStart 方法中,我们可以做很多事情,例如:创建后台或用户中心的菜单 + * + * 此方法是每次项目启动,都会执行。 + * + * 同时用户也可以在后台触发 + */ + + //System.out.println("HelloWorldAddon onStart"); + } + + @Override + public void onStop(AddonInfo addonInfo) { + + /** + * 和 onStart 对应,在 onStart 所处理的事情,在 onStop 应该释放 + * + * 同时用户也可以在后台触发 + */ + + //System.out.println("HelloWorldAddon onStop"); + + } +} diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddonHandler.java b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddonHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..ab8ecd24087bb129e4f1f211dbed47e0de2a9045 --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddonHandler.java @@ -0,0 +1,16 @@ +package org.jpress.addon.menutag; + + +import com.jfinal.handler.Handler; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +public class MenuTagAddonHandler extends Handler { + @Override + public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { + //System.out.println("HelloWorldAddonHandler invoked for target : " + target); + next.handle(target, request, response, isHandled); + } +} diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddonInterceptor.java b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddonInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..b2be334d60794acca8fab825f5c7627b8b9163aa --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagAddonInterceptor.java @@ -0,0 +1,17 @@ +package org.jpress.addon.menutag; + + +import com.jfinal.aop.Interceptor; +import com.jfinal.aop.Invocation; + + +public class MenuTagAddonInterceptor implements Interceptor { + + @Override + public void intercept(Invocation inv) { + + //System.out.println("HelloWorldAddonInterceptor invoke"); + + inv.invoke(); + } +} diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagController.java b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagController.java new file mode 100644 index 0000000000000000000000000000000000000000..3a4188f9895c6cd82f1132f4e945d8331b7d3a1c --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagController.java @@ -0,0 +1,146 @@ +package org.jpress.addon.menutag; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import java.util.List; + +import com.aliyun.oss.model.LiveChannelStat.VideoStat; +import com.jfinal.core.ActionKey; +import com.jfinal.kit.Ret; + +import io.jboot.web.controller.annotation.RequestMapping; +import io.jpress.JPressConsts; +import io.jpress.core.menu.annotation.AdminMenu; +import io.jpress.core.template.Template; +import io.jpress.core.template.TemplateManager; +import io.jpress.web.base.AdminControllerBase; + + +@RequestMapping(value = "/admin/addon/menuTag" ,viewPath = "/") +public class MenuTagController extends AdminControllerBase { + private static final List resources = Arrays.asList(new String[] {"page_menuTag.html", "plugin-menuTag"}); + + @ActionKey("/admin/addon/menuTag") + @AdminMenu(groupId = JPressConsts.SYSTEM_MENU_ADDON, text = "菜单标签插件") + public void index() { + render("setting.html"); +// setAttr("version","1.0.0"); +// renderText("index"); + } + + public void json() { + renderJson(Ret.ok().set("message", "json ok....")); + } + + public void checkPlugin() { + Template curTemplate = TemplateManager.me().getCurrentTemplate(); + File templateDir = curTemplate.getAbsolutePathFile(); + + File[] htmls = templateDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".html")); + boolean applied = false; + for(File html: htmls) { + if(html.getName().equals("page_menuTag.html")) { + applied = true; + break; + } + } + + if(applied) { + renderJson(Ret.ok().set("code", 1)); + }else { + renderJson(Ret.ok().set("code", 0)); + } + } + + public void applyPlugin() { + Template curTemplate = TemplateManager.me().getCurrentTemplate(); + File templateDir = curTemplate.getAbsolutePathFile(); + File parentFile = templateDir.getParentFile(); + while(!parentFile.getName().equals("templates")) { + parentFile = parentFile.getParentFile(); + } + // 网站根目录 + parentFile = parentFile.getParentFile(); + + File pluginResource = new File(parentFile.getAbsolutePath() + + File.separator + "addons" + File.separator + "io.jpress.addon.menuTag", "resource"); + + try + { + if(pluginResource.isDirectory()) { + for(File resource: pluginResource.listFiles()) { + if(resource.isDirectory()) { + File temp = new File(templateDir, resource.getName()); + if(!temp.exists()) { + temp.mkdir(); + } + for(File sub: resource.listFiles()) { + File temp2 = new File(templateDir.getAbsolutePath() + File.separator + + resource.getName(), sub.getName()); + Files.copy(sub.toPath(), temp2.toPath(), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + } + }else { + File temp = new File(templateDir, resource.getName()); + Files.copy(resource.toPath(), temp.toPath(), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + } + } + } + + curTemplate.refresh(); + } + catch(IOException e) + { + e.printStackTrace(); + renderJson(Ret.ok().set("code", 0)); + return; + } + + renderJson(Ret.ok().set("code", 1)); + } + + public void removePlugin() { + Template curTemplate = TemplateManager.me().getCurrentTemplate(); + File templateDir = curTemplate.getAbsolutePathFile(); + + deleteFiles(templateDir, resources); + curTemplate.refresh(); + + renderJson(Ret.ok().set("code", 1)); + } + + // 从模板中找插件文件并删除 + private void deleteFiles(File dir, List deletes) { + boolean deleted = false; + for(String del: deletes) { + if(dir.getName().startsWith(del)) { + deletePlugin(dir); + deleted = true; + break; + } + } + + if(!deleted && dir.isDirectory()) { + for(File f: dir.listFiles()) { + deleteFiles(f, deletes); + } + } + } + + // 删除插件文件 + private void deletePlugin(File dir) { + if(dir.isDirectory()) { + for(File f: dir.listFiles()) { + if(f.isFile()) { + f.delete(); + }else { + deletePlugin(f); + } + } + } + + dir.delete(); + } +} diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagUpgrader.java b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagUpgrader.java new file mode 100644 index 0000000000000000000000000000000000000000..960b3ada4fea474040faa205e0fdac487507dbf0 --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/java/org/jpress/addon/menutag/MenuTagUpgrader.java @@ -0,0 +1,18 @@ +package org.jpress.addon.menutag; + +import io.jpress.core.addon.AddonInfo; +import io.jpress.core.addon.AddonUpgrader; + + +public class MenuTagUpgrader implements AddonUpgrader { + @Override + public boolean onUpgrade(AddonInfo oldAddon, AddonInfo thisAddon) { + //System.out.println("HelloWorldUpgrader.onUpgrade()"); + return true; + } + + @Override + public void onRollback(AddonInfo oldAddon, AddonInfo thisAddon) { + //System.out.println("HelloWorldUpgrader.onRollback()"); + } +} diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/resources/addon.txt b/jpress-addons/jpress-addon-categoryTag/src/main/resources/addon.txt new file mode 100644 index 0000000000000000000000000000000000000000..fcef41d63c27a6df7b6d487203efedd6c7d06445 --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/resources/addon.txt @@ -0,0 +1,7 @@ +id=io.jpress.addon.menuTag +title=菜单标签插件 +description=文章的菜单和标签,简单使用后端数据制作 +author=almond +authorWebsite= +version=1.1.0 +versionCode=10100 \ No newline at end of file diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/resources/changelog.txt b/jpress-addons/jpress-addon-categoryTag/src/main/resources/changelog.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4f3ec85e17d8c28fb9873e025389f6441f35989 --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/resources/changelog.txt @@ -0,0 +1,20 @@ +## v1.1.0 +#### 修改分类为菜单: +* 因为网站中是显示菜单和标签,菜单只是部分内容来自分类,所以改成菜单 + +## v1.0.2 +#### 完善插件: +* 增加插件使用说明与升级日志 + +## v1.0.1 +#### 修复bug: +* 当模板template.properties文件也即模板内容不再模板第一级目录下,无法使用的问题 +* 插件页面显示乱码的问题 + +#### 优化: +* 优化页面显示 + +## v1.0.0 +#### 完成基本功能: +* 网站分类(菜单)和标签的展示 +* 可以后台设置当前主题使用该插件,可以设置移除该插件 \ No newline at end of file diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/resources/readme.txt b/jpress-addons/jpress-addon-categoryTag/src/main/resources/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f8a84abc00b4c33e0c8114c5e89089fb5f1580b --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/resources/readme.txt @@ -0,0 +1,10 @@ +## 插件信息 +* 插件功能是获取网站的菜单信息和标签信息,并显示到一个网页中 +* 安装插件后,在插件菜单下会出现菜单标签菜单,点击进入,选择将插件页面安装到当前主题 +* 然后需要新建一个页面,样式选择menu_tag,url路径填写menuTag +* 然后浏览器打开 **网站域名/menuTag** 查看效果 +* 如果效果不正常,可能是你所用的模板的问题 +* 该插件页面要求使用bootstarp4,使用layout.html页面(模板的一级目录下) +* 如果不想再使用该插件,请到设置页面移除该插件,移除只会移除文件及目录,请不要在插件目录下放其它文件 +* 页面的效果是下面这样的 +![](/addons/io.jpress.addon.menuTag/resource/menuTag.gif) \ No newline at end of file diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/webapp/menuTag.gif b/jpress-addons/jpress-addon-categoryTag/src/main/webapp/menuTag.gif new file mode 100644 index 0000000000000000000000000000000000000000..110d6e075c16ddb67798fd28c855d5473967d54f Binary files /dev/null and b/jpress-addons/jpress-addon-categoryTag/src/main/webapp/menuTag.gif differ diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/webapp/resource/page_menuTag.html b/jpress-addons/jpress-addon-categoryTag/src/main/webapp/resource/page_menuTag.html new file mode 100644 index 0000000000000000000000000000000000000000..e001834cd24e0caf8ed2c88a55c11e0aafc850d2 --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/webapp/resource/page_menuTag.html @@ -0,0 +1,84 @@ +#include("./layout.html") +#@layout() + +#define css() + +#end + +#define content() +
    +
    +
    +
    +
    #(page.title)
    +
    #(page.view_count)人浏览
    +
    + +
    +
    + 菜单 +
    + #for(menu : MENUS) + #if(menu.isTop()) +
    + #if(!menu.hasChild())#(menu.text) #else #(menu.text) #end + #for(child: menu.childs) +
    +      #if(!child.hasChild())#(child.text) #else #(child.text) #end + #for(child2: child.childs) +
    +           #if(!child2.hasChild())#(child2.text) #else #(child2.text) #end + #for(child3: child2.childs) +
    +                #if(!child3.hasChild())#(child3.text) #else #(child3.text) #end + #for(child4: child3.childs) +
    +                     #(child4.text) +
    + #end +
    + #end +
    + #end +
    + #end +
    + #end + #end + + #tags(count = 9999) +
    + 文章标签 +
    +
    + + #for(tag: tags) + #if(for.index % 3 == 0)#end + + #if(for.index % 3 == 2)#end + #if(for.count == for.size && for.index % 3 != 2) #end + #end +
    #(tag.title) | 共#(tag.count)篇文章
    +
    + #end + + #productTags(count = 9999) +
    + 产品标签 +
    +
    + + #for(tag: tags) + #if(for.index % 3 == 0)#end + + #if(for.index % 3 == 2)#end + #if(for.count == for.size && for.index % 3 != 2) #end + #end +
    #(tag.title) | 共#(tag.count)篇文章
    +
    + #end +
    +
    +
    +
    +#end \ No newline at end of file diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/webapp/resource/plugin-menuTag/plugin-menuTag.css b/jpress-addons/jpress-addon-categoryTag/src/main/webapp/resource/plugin-menuTag/plugin-menuTag.css new file mode 100644 index 0000000000000000000000000000000000000000..d1fdb8b4e1a2ad32a968c8bb868ef78edab30d0a --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/webapp/resource/plugin-menuTag/plugin-menuTag.css @@ -0,0 +1,78 @@ +.shadow-blink{ + animation: shadow-blink 1s linear infinite; +} + + @keyframes shadow-blink { + 0%{ text-shadow: 0 0 4px #4cc134} + 50%{ text-shadow: 0 0 40px #4cc134} + 100%{ text-shadow: 0 0 4px #4cc134} +} +.slide-blink{ + display: inline-block; + background: linear-gradient(90deg, rgba(76,193,34,0), rgba(76,193,34,1)); + animation:slide-blink 0.5s linear forwards infinite; +} +@keyframes slide-blink { + 0% { + background-position: 0 0; + } + 25% { + background-position: 0 0; + } + 26% { + background-position: 20px -20px; + } + 50% { + background-position: 20px -20px; + } + 51% { + background-position: 40px -40px; + } + 75% { + background-position: 40px -40px; + } + 76% { + background-position: 60px -60px; + } + 99% { + background-position: 60px -60px; + } + 100% { + background-position: 0 0; + } +} +.menu-one{ + font-size: 2rem; + margin: 5px 0 5px 0; +} +.menu-two{ + font-size: 1.75rem; + margin: 5px 0 5px 0; +} +.menu-three{ + font-size: 1.5rem; + margin: 5px 0 5px 0; +} +.menu-four{ + font-size: 1.25rem; + margin: 5px 0 5px 0; +} +.menu-link{ + color: #4cc134; +} +.menu-link:hover { + color: #FF9400; + text-decoration: underline; +} +.fitc{ + width:fit-content; +} +.bgo-3{ + background:rgba(248,249,250,0.5); +} +.fb{ + font-weight: bold; +} +.h-1{ + font-size: 2.5rem; +} \ No newline at end of file diff --git a/jpress-addons/jpress-addon-categoryTag/src/main/webapp/setting.html b/jpress-addons/jpress-addon-categoryTag/src/main/webapp/setting.html new file mode 100644 index 0000000000000000000000000000000000000000..9bf1c161db79ee9c1dbc385b733dcc92f378940d --- /dev/null +++ b/jpress-addons/jpress-addon-categoryTag/src/main/webapp/setting.html @@ -0,0 +1,98 @@ +#@layout() + +#define script() + +#end + +#define content() +
    + +
    +

    菜单标签插件设置 Plugin Setting

    +
    + +
    + +
    +
    +
    +
    + +      + +

    +
    +
    + 100% 完成 +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + 作者:almond,如有疑问,请联系:QQ2589071709 +
    +
    +
    +
    + +
    + +
    +#end diff --git a/jpress-addons/jpress-addon-helloworld/pom.xml b/jpress-addons/jpress-addon-helloworld/pom.xml index 24dbbacc4b529fafaf6c33a63e12c2498a1b0761..7da5946fce18862fea3e2e7ea1d650a2d450e3a4 100644 --- a/jpress-addons/jpress-addon-helloworld/pom.xml +++ b/jpress-addons/jpress-addon-helloworld/pom.xml @@ -1,46 +1,46 @@ - - - - jpress-addons - io.jpress - 3.0 - - 4.0.0 - - io.jpress - jpress-addon-helloworld - - - - io.jpress - jpress-core - - - - - - - - - src/main/resources - - **/*.* - - false - - - - src/main/webapp - - **/*.* - - false - - - - - - + + + + jpress-addons + io.jpress + 3.0 + + 4.0.0 + + io.jpress + jpress-addon-helloworld + + + + io.jpress + jpress-core + + + + + + + + + src/main/resources + + **/*.* + + false + + + + src/main/webapp + + **/*.* + + false + + + + + + \ No newline at end of file diff --git a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddon.java b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddon.java index 7f10f39b743fe6ca7993cb93b246915c527567ff..f3a2929045ff3694680c9bfceee0c26ee756bf5e 100644 --- a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddon.java +++ b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddon.java @@ -1,63 +1,63 @@ -package io.jpress.addon.helloworld; - -import io.jpress.core.addon.Addon; -import io.jpress.core.addon.AddonInfo; - -/** - * 这是一个 JPress 插件的 hello world 项目,没有具体的功能。 - * - * 其存在的目的是为了帮助开发者,通过 hello world ,了解如何开发一个 JPress 插件 - * - */ -public class HelloWorldAddon implements Addon { - - @Override - public void onInstall(AddonInfo addonInfo) { - - /** - * 在 onInstall ,我们一般需要 创建自己的数据表 - * - * onInstall 方法只会执行一次,执行完毕之后不会再执行,除非是用户卸载插件再次安装 - */ - System.out.println("HelloWorldAddon onInstall"); - - } - - @Override - public void onUninstall(AddonInfo addonInfo) { - - /** - * 在 onUninstall 中,我们一般需要去删除自己在 onInstall 中创建的表 或者 其他资源文件 - * 这个方法是用户在 Jpress 后台卸载插件的时候回触发。 - */ - - System.out.println("HelloWorldAddon onUninstall"); - } - - @Override - public void onStart(AddonInfo addonInfo) { - - /** - * 在 onStart 方法中,我们可以做很多事情,例如:创建后台或用户中心的菜单 - * - * 此方法是每次项目启动,都会执行。 - * - * 同时用户也可以在后台触发 - */ - - System.out.println("HelloWorldAddon onStart"); - } - - @Override - public void onStop(AddonInfo addonInfo) { - - /** - * 和 onStart 对应,在 onStart 所处理的事情,在 onStop 应该释放 - * - * 同时用户也可以在后台触发 - */ - - System.out.println("HelloWorldAddon onStop"); - - } -} +package io.jpress.addon.helloworld; + +import io.jpress.core.addon.Addon; +import io.jpress.core.addon.AddonInfo; + +/** + * 这是一个 JPress 插件的 hello world 项目,没有具体的功能。 + * + * 其存在的目的是为了帮助开发者,通过 hello world ,了解如何开发一个 JPress 插件 + * + */ +public class HelloWorldAddon implements Addon { + + @Override + public void onInstall(AddonInfo addonInfo) { + + /** + * 在 onInstall ,我们一般需要 创建自己的数据表 + * + * onInstall 方法只会执行一次,执行完毕之后不会再执行,除非是用户卸载插件再次安装 + */ + System.out.println("HelloWorldAddon onInstall"); + + } + + @Override + public void onUninstall(AddonInfo addonInfo) { + + /** + * 在 onUninstall 中,我们一般需要去删除自己在 onInstall 中创建的表 或者 其他资源文件 + * 这个方法是用户在 Jpress 后台卸载插件的时候回触发。 + */ + + System.out.println("HelloWorldAddon onUninstall"); + } + + @Override + public void onStart(AddonInfo addonInfo) { + + /** + * 在 onStart 方法中,我们可以做很多事情,例如:创建后台或用户中心的菜单 + * + * 此方法是每次项目启动,都会执行。 + * + * 同时用户也可以在后台触发 + */ + + System.out.println("HelloWorldAddon onStart"); + } + + @Override + public void onStop(AddonInfo addonInfo) { + + /** + * 和 onStart 对应,在 onStart 所处理的事情,在 onStop 应该释放 + * + * 同时用户也可以在后台触发 + */ + + System.out.println("HelloWorldAddon onStop"); + + } +} diff --git a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonController.java b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonController.java index 07624a0baa3858e47651965e009e594da068dc9e..cd49261290ab0fd5c9908827b1754a33fb4bbf38 100644 --- a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonController.java +++ b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonController.java @@ -1,28 +1,28 @@ -package io.jpress.addon.helloworld; - -import com.jfinal.core.ActionKey; -import com.jfinal.kit.Ret; -import io.jboot.web.controller.JbootController; -import io.jboot.web.controller.annotation.RequestMapping; -import io.jpress.JPressConsts; -import io.jpress.core.menu.annotation.AdminMenu; - - -@RequestMapping(value = "/helloworld",viewPath = "/") -public class HelloWorldAddonController extends JbootController { - - public void index() { - setAttr("version","1.0.2"); - render("helloworld/index.html"); - } - - public void json() { - renderJson(Ret.ok().set("message", "json ok....")); - } - - @ActionKey("/admin/addon/test") - @AdminMenu(groupId = JPressConsts.SYSTEM_MENU_ADDON, text = "插件测试") - public void adminmenutest() { - renderText("addon test abc"); - } -} +package io.jpress.addon.helloworld; + +import com.jfinal.core.ActionKey; +import com.jfinal.kit.Ret; +import io.jboot.web.controller.JbootController; +import io.jboot.web.controller.annotation.RequestMapping; +import io.jpress.JPressConsts; +import io.jpress.core.menu.annotation.AdminMenu; + + +@RequestMapping(value = "/helloworld",viewPath = "/") +public class HelloWorldAddonController extends JbootController { + + public void index() { + setAttr("version","1.0.2"); + render("helloworld/index.html"); + } + + public void json() { + renderJson(Ret.ok().set("message", "json ok....")); + } + + @ActionKey("/admin/addon/test") + @AdminMenu(groupId = JPressConsts.SYSTEM_MENU_ADDON, text = "插件测试") + public void adminmenutest() { + renderText("addon test abc"); + } +} diff --git a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonHandler.java b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonHandler.java index 687fcbcf5b58cf3d2594677f3eacad45f0dcc0a2..8b57bd9710bf6823388756b48bdb2fcbaeec0f14 100644 --- a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonHandler.java +++ b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonHandler.java @@ -1,16 +1,16 @@ -package io.jpress.addon.helloworld; - - -import com.jfinal.handler.Handler; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - - -public class HelloWorldAddonHandler extends Handler { - @Override - public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { - System.out.println("HelloWorldAddonHandler invoked for target : " + target); - next.handle(target, request, response, isHandled); - } -} +package io.jpress.addon.helloworld; + + +import com.jfinal.handler.Handler; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +public class HelloWorldAddonHandler extends Handler { + @Override + public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { + System.out.println("HelloWorldAddonHandler invoked for target : " + target); + next.handle(target, request, response, isHandled); + } +} diff --git a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonInterceptor.java b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonInterceptor.java index fa1e3ae6e95c923bf6f44abb70ab21b552108dc2..794966e90b3e419df69e19e24de7110b033392d4 100644 --- a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonInterceptor.java +++ b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldAddonInterceptor.java @@ -1,17 +1,17 @@ -package io.jpress.addon.helloworld; - - -import com.jfinal.aop.Interceptor; -import com.jfinal.aop.Invocation; - - -public class HelloWorldAddonInterceptor implements Interceptor { - - @Override - public void intercept(Invocation inv) { - - System.out.println("HelloWorldAddonInterceptor invoke"); - - inv.invoke(); - } -} +package io.jpress.addon.helloworld; + + +import com.jfinal.aop.Interceptor; +import com.jfinal.aop.Invocation; + + +public class HelloWorldAddonInterceptor implements Interceptor { + + @Override + public void intercept(Invocation inv) { + + System.out.println("HelloWorldAddonInterceptor invoke"); + + inv.invoke(); + } +} diff --git a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldUpgrader.java b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldUpgrader.java index abbff700bfd4a6af83bf33f5f46bde5e9b0f8ce0..10a86f6c7c1d97d54303175d80108559b830e45f 100644 --- a/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldUpgrader.java +++ b/jpress-addons/jpress-addon-helloworld/src/main/java/io/jpress/addon/helloworld/HelloWorldUpgrader.java @@ -1,18 +1,18 @@ -package io.jpress.addon.helloworld; - -import io.jpress.core.addon.AddonInfo; -import io.jpress.core.addon.AddonUpgrader; - - -public class HelloWorldUpgrader implements AddonUpgrader { - @Override - public boolean onUpgrade(AddonInfo oldAddon, AddonInfo thisAddon) { - System.out.println("HelloWorldUpgrader.onUpgrade()"); - return true; - } - - @Override - public void onRollback(AddonInfo oldAddon, AddonInfo thisAddon) { - System.out.println("HelloWorldUpgrader.onRollback()"); - } -} +package io.jpress.addon.helloworld; + +import io.jpress.core.addon.AddonInfo; +import io.jpress.core.addon.AddonUpgrader; + + +public class HelloWorldUpgrader implements AddonUpgrader { + @Override + public boolean onUpgrade(AddonInfo oldAddon, AddonInfo thisAddon) { + System.out.println("HelloWorldUpgrader.onUpgrade()"); + return true; + } + + @Override + public void onRollback(AddonInfo oldAddon, AddonInfo thisAddon) { + System.out.println("HelloWorldUpgrader.onRollback()"); + } +} diff --git a/jpress-addons/jpress-addon-helloworld/src/main/resources/addon.txt b/jpress-addons/jpress-addon-helloworld/src/main/resources/addon.txt index 5c28bee22979fcdafb0d4f5e0003348387054d31..92fb9aee095d28fe9da3dea991c395abf59e1a56 100644 --- a/jpress-addons/jpress-addon-helloworld/src/main/resources/addon.txt +++ b/jpress-addons/jpress-addon-helloworld/src/main/resources/addon.txt @@ -1,7 +1,7 @@ -id=io.jpress.addon.helloworld -title=hello world -description=这只是一个插件demo,方便开发者参考开发2222 -author=海哥 -authorWebsite= -version=1.0.3 +id=io.jpress.addon.helloworld +title=hello world +description=这只是一个插件demo,方便开发者参考开发2222 +author=海哥 +authorWebsite= +version=1.0.3 versionCode=3 \ No newline at end of file diff --git a/jpress-addons/jpress-addon-helloworld/src/main/resources/config.txt b/jpress-addons/jpress-addon-helloworld/src/main/resources/config.txt index fca3e1c3560535d4208d7bb11c991e2c06b66ab4..6bf34c85a923c69f6499bbd7b57aabb0a0ad3bb5 100644 --- a/jpress-addons/jpress-addon-helloworld/src/main/resources/config.txt +++ b/jpress-addons/jpress-addon-helloworld/src/main/resources/config.txt @@ -1,25 +1,25 @@ -db.type = mysql -db.url -db.user -db.password -db.driverClassName = "com.mysql.jdbc.Driver" -db.connectionInitSql -db.poolName -db.cachePrepStmts = true -db.prepStmtCacheSize = 500 -db.prepStmtCacheSqlLimit = 2048 -db.maximumPoolSize = 10 -db.maxLifetime -db.idleTimeout -db.minimumIdle = 0 -db.sqlTemplatePath -db.sqlTemplate -db.factory -db.shardingConfigYaml -db.dbProFactory -db.containerFactory -db.transactionLevel -db.table #此数据源包含哪些表,这个配置会覆盖@Table注解的配置 -db.exTable #该数据源排除哪些表,这个配置会修改掉@Table上的配置 -db.dialectClass +db.type = mysql +db.url +db.user +db.password +db.driverClassName = "com.mysql.jdbc.Driver" +db.connectionInitSql +db.poolName +db.cachePrepStmts = true +db.prepStmtCacheSize = 500 +db.prepStmtCacheSqlLimit = 2048 +db.maximumPoolSize = 10 +db.maxLifetime +db.idleTimeout +db.minimumIdle = 0 +db.sqlTemplatePath +db.sqlTemplate +db.factory +db.shardingConfigYaml +db.dbProFactory +db.containerFactory +db.transactionLevel +db.table #此数据源包含哪些表,这个配置会覆盖@Table注解的配置 +db.exTable #该数据源排除哪些表,这个配置会修改掉@Table上的配置 +db.dialectClass db.activeRecordPluginClass \ No newline at end of file diff --git a/jpress-addons/jpress-addon-helloworld/src/main/webapp/helloworld/index.html b/jpress-addons/jpress-addon-helloworld/src/main/webapp/helloworld/index.html index 1773dd1ccf401464941c875f6839e43104ff925c..bb32eb992a8648fa77c5fbad85aba43d7cd7583a 100644 --- a/jpress-addons/jpress-addon-helloworld/src/main/webapp/helloworld/index.html +++ b/jpress-addons/jpress-addon-helloworld/src/main/webapp/helloworld/index.html @@ -1,12 +1,12 @@ - - - - - hello world addon - - - -hello addon in html. addon version #(version). - - + + + + + hello world addon + + + +hello addon in html. addon version #(version). + + \ No newline at end of file diff --git a/jpress-addons/jpress-addon-message/LICENSE b/jpress-addons/jpress-addon-message/LICENSE index 65c5ca88a67c30becee01c5a8816d964b03862f9..b14ca0a552d7e97012befc8f4949173e6ace87c9 100644 --- a/jpress-addons/jpress-addon-message/LICENSE +++ b/jpress-addons/jpress-addon-message/LICENSE @@ -1,165 +1,165 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/jpress-addons/jpress-addon-message/README.md b/jpress-addons/jpress-addon-message/README.md index 0c4faeccda8b1501bad404a0bbf87fcd1faa866b..39e6cf72db81323957acb711efd3531a32bc44f6 100644 --- a/jpress-addons/jpress-addon-message/README.md +++ b/jpress-addons/jpress-addon-message/README.md @@ -1,27 +1,27 @@ -用于jpress的拓展插件主要实现了用户提交留言的功能 - -代码示例:获取用户留言的列表 -``` -#messageList() -#for(msg : messageList) -
    -
    -
    -
    -
    #(msg.name ??)
    - -
    -
    -

    #(msg.message ??)

    -
    -
    -
    -
    -#end -#end -``` -提交留言接口地址: /msgController - - -![输入图片说明](https://images.gitee.com/uploads/images/2020/0226/214527_cc2a8636_2147597.png "屏幕截图.png") +用于jpress的拓展插件主要实现了用户提交留言的功能 + +代码示例:获取用户留言的列表 +``` +#messageList() +#for(msg : messageList) +
    +
    +
    +
    +
    #(msg.name ??)
    + +
    +
    +

    #(msg.message ??)

    +
    +
    +
    +
    +#end +#end +``` +提交留言接口地址: /msgController + + +![输入图片说明](https://images.gitee.com/uploads/images/2020/0226/214527_cc2a8636_2147597.png "屏幕截图.png") ![输入图片说明](https://images.gitee.com/uploads/images/2020/0226/214555_963e756a_2147597.png "屏幕截图.png") \ No newline at end of file diff --git a/jpress-addons/jpress-addon-message/pom.xml b/jpress-addons/jpress-addon-message/pom.xml index cb645346e0ef42ee6a7ce68afd187e4014aef4d1..b4d3cc512a73b3f47089020f199023c358c8d72e 100644 --- a/jpress-addons/jpress-addon-message/pom.xml +++ b/jpress-addons/jpress-addon-message/pom.xml @@ -1,51 +1,51 @@ - - - - jpress-addons - io.jpress - 3.0 - - 4.0.0 - - jpress-addon-message - - - - - io.jpress - jpress-core - - - io.jpress - codegen - 3.0 - compile - - - - - - - - - src/main/resources - - **/*.* - - false - - - - src/main/webapp - - **/*.* - - false - - - - - - + + + + jpress-addons + io.jpress + 3.0 + + 4.0.0 + + jpress-addon-message + + + + + io.jpress + jpress-core + + + io.jpress + codegen + 3.0 + compile + + + + + + + + + src/main/resources + + **/*.* + + false + + + + src/main/webapp + + **/*.* + + false + + + + + + diff --git a/jpress-addons/jpress-addon-message/src/main/java/Codegen.java b/jpress-addons/jpress-addon-message/src/main/java/Codegen.java index 375f713e5d91d2649e9713487a0c5445a331a84c..20cc0adb7059302b6a315c1a9d588bdbaf9c7bf2 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/Codegen.java +++ b/jpress-addons/jpress-addon-message/src/main/java/Codegen.java @@ -1,23 +1,23 @@ -import io.jpress.codegen.AddonGenerator; - -public class Codegen { - - private static String dbUrl = "jdbc:mysql://127.0.0.1:3306/jpress3dev"; - private static String dbUser = "root"; - private static String dbPassword = "123456"; - - private static String addonName = "message"; - private static String dbTables = "jpress_addon_message"; - private static String modelPackage = "io.jpress.addon.message.model"; - private static String servicePackage = "io.jpress.addon.message.service"; - - - public static void main(String[] args) { - - AddonGenerator moduleGenerator = new AddonGenerator(addonName, dbUrl, dbUser, dbPassword, dbTables, modelPackage, servicePackage); -// moduleGenerator.setGenUI(true); - moduleGenerator.gen(); - - } - -} +import io.jpress.codegen.AddonGenerator; + +public class Codegen { + + private static String dbUrl = "jdbc:mysql://127.0.0.1:3306/jpress3dev"; + private static String dbUser = "root"; + private static String dbPassword = "123456"; + + private static String addonName = "message"; + private static String dbTables = "jpress_addon_message"; + private static String modelPackage = "io.jpress.addon.message.model"; + private static String servicePackage = "io.jpress.addon.message.service"; + + + public static void main(String[] args) { + + AddonGenerator moduleGenerator = new AddonGenerator(addonName, dbUrl, dbUser, dbPassword, dbTables, modelPackage, servicePackage); +// moduleGenerator.setGenUI(true); + moduleGenerator.gen(); + + } + +} diff --git a/jpress-addons/jpress-addon-message/src/main/java/MessageAddon.java b/jpress-addons/jpress-addon-message/src/main/java/MessageAddon.java index 6f7c9e69cd81185a5d48aa872face83e80aa956a..086fb127180988bdf525b0f4dd9d557ca7c00586 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/MessageAddon.java +++ b/jpress-addons/jpress-addon-message/src/main/java/MessageAddon.java @@ -1,64 +1,64 @@ -import com.jfinal.render.RenderManager; -import io.jpress.JPressConsts; -import io.jpress.core.addon.Addon; -import io.jpress.core.addon.AddonInfo; -import io.jpress.core.addon.AddonUtil; -import io.jpress.core.menu.MenuGroup; -import io.jpress.core.menu.MenuManager; - -import java.sql.SQLException; - -/** - *留言信息插件 - */ -public class MessageAddon implements Addon { - - @Override - public void onInstall(AddonInfo addonInfo) { - try { - AddonUtil.execSqlFile(addonInfo, "sql/install.sql"); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - - @Override - public void onUninstall(AddonInfo addonInfo) { - try { - AddonUtil.execSqlFile(addonInfo, "sql/uninstall.sql"); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - @Override - public void onStart(AddonInfo addonInfo) { - - /** - * 在 onStart 方法中,我们可以做很多事情,例如:创建后台或用户中心的菜单 - * - * 此方法是每次项目启动,都会执行。 - * - * 同时用户也可以在后台触发 - */ - MenuGroup orderMenuGroup = new MenuGroup(); - orderMenuGroup.setId("message"); - orderMenuGroup.setText("留言管理"); - orderMenuGroup.setIcon(""); - MenuManager.me().getModuleMenus().add(orderMenuGroup); - - } - - @Override - public void onStop(AddonInfo addonInfo) { - - /** - * 和 onStart 对应,在 onStart 所处理的事情,在 onStop 应该释放 - * - * 同时用户也可以在后台触发 - */ - MenuManager.me().deleteMenuGroup("message"); - - } -} +import com.jfinal.render.RenderManager; +import io.jpress.JPressConsts; +import io.jpress.core.addon.Addon; +import io.jpress.core.addon.AddonInfo; +import io.jpress.core.addon.AddonUtil; +import io.jpress.core.menu.MenuGroup; +import io.jpress.core.menu.MenuManager; + +import java.sql.SQLException; + +/** + *留言信息插件 + */ +public class MessageAddon implements Addon { + + @Override + public void onInstall(AddonInfo addonInfo) { + try { + AddonUtil.execSqlFile(addonInfo, "sql/install.sql"); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + + @Override + public void onUninstall(AddonInfo addonInfo) { + try { + AddonUtil.execSqlFile(addonInfo, "sql/uninstall.sql"); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onStart(AddonInfo addonInfo) { + + /** + * 在 onStart 方法中,我们可以做很多事情,例如:创建后台或用户中心的菜单 + * + * 此方法是每次项目启动,都会执行。 + * + * 同时用户也可以在后台触发 + */ + MenuGroup orderMenuGroup = new MenuGroup(); + orderMenuGroup.setId("message"); + orderMenuGroup.setText("留言管理"); + orderMenuGroup.setIcon(""); + MenuManager.me().getModuleMenus().add(orderMenuGroup); + + } + + @Override + public void onStop(AddonInfo addonInfo) { + + /** + * 和 onStart 对应,在 onStart 所处理的事情,在 onStop 应该释放 + * + * 同时用户也可以在后台触发 + */ + MenuManager.me().deleteMenuGroup("message"); + + } +} diff --git a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/controller/MessageController.java b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/controller/MessageController.java index 08298f9e9dcbfeedc6ccdcc78af1cdeb19af9c86..0b5f303f5e663204663f109858ef49b8e9204479 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/controller/MessageController.java +++ b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/controller/MessageController.java @@ -1,56 +1,56 @@ -package io.jpress.addon.message.controller; - -import com.jfinal.aop.Inject; -import com.jfinal.kit.Ret; -import io.jboot.utils.StrUtil; -import io.jboot.web.controller.JbootController; -import io.jboot.web.controller.annotation.RequestMapping; -import io.jpress.addon.message.model.JpressAddonMessage; -import io.jpress.addon.message.service.JpressAddonMessageService; -import io.jpress.commons.utils.CommonsUtils; - -/** - * anjie 2020年2月24日 - */ -@RequestMapping(value = "/msgController",viewPath = "/") -public class MessageController extends JbootController{ - - @Inject - private JpressAddonMessageService service; - - public void doSave() { - - JpressAddonMessage entry = getModel(JpressAddonMessage.class); - //防止xss注入攻击 - CommonsUtils.escapeModel(entry); - - if(StrUtil.isBlank(entry.getName())){ - renderJson(Ret.fail().set("msg","对不起名字不能是空")); - return; - } - - if(StrUtil.isBlank(entry.getPhone())){ - renderJson(Ret.fail().set("msg","对不起电话不能是空")); - return; - } - if(StrUtil.isBlank(entry.getEmail())){ - renderJson(Ret.fail().set("msg","对不起邮箱不能是空")); - return; - } - if(StrUtil.isBlank(entry.getTitle())){ - renderJson(Ret.fail().set("msg","对不起标题不能是空")); - return; - } - if(StrUtil.isBlank(entry.getContent())){ - renderJson(Ret.fail().set("msg","对不起留言不能是空")); - return; - } - - entry.setShow(false); - - service.save(entry); - - renderJson(Ret.ok()); - } - -} +package io.jpress.addon.message.controller; + +import com.jfinal.aop.Inject; +import com.jfinal.kit.Ret; +import io.jboot.utils.StrUtil; +import io.jboot.web.controller.JbootController; +import io.jboot.web.controller.annotation.RequestMapping; +import io.jpress.addon.message.model.JpressAddonMessage; +import io.jpress.addon.message.service.JpressAddonMessageService; +import io.jpress.commons.utils.CommonsUtils; + +/** + * anjie 2020年2月24日 + */ +@RequestMapping(value = "/msgController",viewPath = "/") +public class MessageController extends JbootController{ + + @Inject + private JpressAddonMessageService service; + + public void doSave() { + + JpressAddonMessage entry = getModel(JpressAddonMessage.class); + //防止xss注入攻击 + CommonsUtils.escapeModel(entry); + + if(StrUtil.isBlank(entry.getName())){ + renderJson(Ret.fail().set("msg","对不起名字不能是空")); + return; + } + + if(StrUtil.isBlank(entry.getPhone())){ + renderJson(Ret.fail().set("msg","对不起电话不能是空")); + return; + } + if(StrUtil.isBlank(entry.getEmail())){ + renderJson(Ret.fail().set("msg","对不起邮箱不能是空")); + return; + } + if(StrUtil.isBlank(entry.getTitle())){ + renderJson(Ret.fail().set("msg","对不起标题不能是空")); + return; + } + if(StrUtil.isBlank(entry.getContent())){ + renderJson(Ret.fail().set("msg","对不起留言不能是空")); + return; + } + + entry.setShow(false); + + service.save(entry); + + renderJson(Ret.ok()); + } + +} diff --git a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/controller/_MessageController.java b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/controller/_MessageController.java index 608f863bbccb734393b20460c5c5a6d7bf93a59b..10e0fa04b63551a4f72e9dad5433fe1c7352f2cc 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/controller/_MessageController.java +++ b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/controller/_MessageController.java @@ -1,75 +1,75 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.addon.message.controller; - -import com.jfinal.aop.Inject; -import com.jfinal.kit.Ret; -import com.jfinal.plugin.activerecord.Page; -import io.jboot.web.controller.annotation.RequestMapping; -import io.jboot.web.validate.EmptyValidate; -import io.jboot.web.validate.Form; -import io.jpress.addon.message.model.JpressAddonMessage; -import io.jpress.addon.message.service.JpressAddonMessageService; -import io.jpress.core.menu.annotation.AdminMenu; -import io.jpress.web.base.AdminControllerBase; - -import java.util.Set; - - -@RequestMapping(value = "/admin/message/jpress_addon_message", viewPath = "/views") -public class _MessageController extends AdminControllerBase { - - @Inject - private JpressAddonMessageService service; - - @AdminMenu(text = "管理", groupId = "message") - public void index() { - Page entries=service.paginate(getPagePara(), 10); - setAttr("page", entries); - render("jpress_addon_message_list.html"); - } - - - public void edit() { - int entryId = getParaToInt(0, 0); - JpressAddonMessage entry = entryId > 0 ? service.findById(entryId) : null; - setAttr("jpressAddonMessage", entry); - render("jpress_addon_message_edit.html"); - } - - public void doSave() { - JpressAddonMessage entry = getModel(JpressAddonMessage.class,"jpressAddonMessage"); - service.saveOrUpdate(entry); - renderJson(Ret.ok().set("id", entry.getId())); - } - - - public void doDel() { - Long id = getIdPara(); - render(service.deleteById(id) ? Ret.ok() : Ret.fail()); - } - - @EmptyValidate(@Form(name = "ids")) - public void doDelByIds() { - Set idsSet = getParaSet("ids"); - if (service.batchDeleteByIds(idsSet.toArray())){ - for (String id : idsSet){ - service.deleteById(Long.valueOf(id)); - } - } - renderOkJson(); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.addon.message.controller; + +import com.jfinal.aop.Inject; +import com.jfinal.kit.Ret; +import com.jfinal.plugin.activerecord.Page; +import io.jboot.web.controller.annotation.RequestMapping; +import io.jboot.web.validate.EmptyValidate; +import io.jboot.web.validate.Form; +import io.jpress.addon.message.model.JpressAddonMessage; +import io.jpress.addon.message.service.JpressAddonMessageService; +import io.jpress.core.menu.annotation.AdminMenu; +import io.jpress.web.base.AdminControllerBase; + +import java.util.Set; + + +@RequestMapping(value = "/admin/message/jpress_addon_message", viewPath = "/views") +public class _MessageController extends AdminControllerBase { + + @Inject + private JpressAddonMessageService service; + + @AdminMenu(text = "管理", groupId = "message") + public void index() { + Page entries=service.paginate(getPagePara(), 10); + setAttr("page", entries); + render("jpress_addon_message_list.html"); + } + + + public void edit() { + int entryId = getParaToInt(0, 0); + JpressAddonMessage entry = entryId > 0 ? service.findById(entryId) : null; + setAttr("jpressAddonMessage", entry); + render("jpress_addon_message_edit.html"); + } + + public void doSave() { + JpressAddonMessage entry = getModel(JpressAddonMessage.class,"jpressAddonMessage"); + service.saveOrUpdate(entry); + renderJson(Ret.ok().set("id", entry.getId())); + } + + + public void doDel() { + Long id = getIdPara(); + render(service.deleteById(id) ? Ret.ok() : Ret.fail()); + } + + @EmptyValidate(@Form(name = "ids")) + public void doDelByIds() { + Set idsSet = getParaSet("ids"); + if (service.batchDeleteByIds(idsSet.toArray())){ + for (String id : idsSet){ + service.deleteById(Long.valueOf(id)); + } + } + renderOkJson(); + } +} diff --git a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/directive/MessageListDirective.java b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/directive/MessageListDirective.java index 8900ec4e01b29afedb02b50a2cf42f58502d90ba..eb1d1a15a220bf41131be0af99760131fb54b706 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/directive/MessageListDirective.java +++ b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/directive/MessageListDirective.java @@ -1,36 +1,36 @@ -package io.jpress.addon.message.directive; - -import com.jfinal.aop.Inject; -import com.jfinal.template.Env; -import com.jfinal.template.io.Writer; -import com.jfinal.template.stat.Scope; -import io.jboot.db.model.Columns; -import io.jboot.web.directive.annotation.JFinalDirective; -import io.jboot.web.directive.base.JbootDirectiveBase; -import io.jpress.addon.message.model.JpressAddonMessage; -import io.jpress.addon.message.service.JpressAddonMessageService; - -import java.util.List; - - -@JFinalDirective("messageList") -public class MessageListDirective extends JbootDirectiveBase { - - @Inject - private JpressAddonMessageService service; - - @Override - public void onRender(Env env, Scope scope, Writer writer) { - - Columns columns = new Columns(); - columns.eq("show", true); - List jpressAddonMessageList = service.findListByColumns(columns); - scope.setLocal("messageList", jpressAddonMessageList); - renderBody(env, scope, writer); - } - - @Override - public boolean hasEnd() { - return true; - } -} +package io.jpress.addon.message.directive; + +import com.jfinal.aop.Inject; +import com.jfinal.template.Env; +import com.jfinal.template.io.Writer; +import com.jfinal.template.stat.Scope; +import io.jboot.db.model.Columns; +import io.jboot.web.directive.annotation.JFinalDirective; +import io.jboot.web.directive.base.JbootDirectiveBase; +import io.jpress.addon.message.model.JpressAddonMessage; +import io.jpress.addon.message.service.JpressAddonMessageService; + +import java.util.List; + + +@JFinalDirective("messageList") +public class MessageListDirective extends JbootDirectiveBase { + + @Inject + private JpressAddonMessageService service; + + @Override + public void onRender(Env env, Scope scope, Writer writer) { + + Columns columns = new Columns(); + columns.eq("show", true); + List jpressAddonMessageList = service.findListByColumns(columns); + scope.setLocal("messageList", jpressAddonMessageList); + renderBody(env, scope, writer); + } + + @Override + public boolean hasEnd() { + return true; + } +} diff --git a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/model/JpressAddonMessage.java b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/model/JpressAddonMessage.java index 257cc62ecfef9bf6adef1e6b652842408e2503a6..48d6fe3f9f393bbe1a50b1d2c2ddaed3b1e150d1 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/model/JpressAddonMessage.java +++ b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/model/JpressAddonMessage.java @@ -1,15 +1,15 @@ -package io.jpress.addon.message.model; - -import io.jboot.db.annotation.Table; -import io.jpress.addon.message.model.base.BaseJpressAddonMessage; - -/** - * Generated by JPress. - */ -@Table(tableName = "jpress_addon_message", primaryKey = "id") -public class JpressAddonMessage extends BaseJpressAddonMessage { - - private static final long serialVersionUID = 1L; - - -} +package io.jpress.addon.message.model; + +import io.jboot.db.annotation.Table; +import io.jpress.addon.message.model.base.BaseJpressAddonMessage; + +/** + * Generated by JPress. + */ +@Table(tableName = "jpress_addon_message", primaryKey = "id") +public class JpressAddonMessage extends BaseJpressAddonMessage { + + private static final long serialVersionUID = 1L; + + +} diff --git a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/model/base/BaseJpressAddonMessage.java b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/model/base/BaseJpressAddonMessage.java index 5fddccf2805a2611b326b5fc81c6e69ff32816ac..919368075986c951facf865a8b8b66c929d46157 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/model/base/BaseJpressAddonMessage.java +++ b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/model/base/BaseJpressAddonMessage.java @@ -1,106 +1,106 @@ -package io.jpress.addon.message.model.base; - -import io.jboot.db.model.JbootModel; -import com.jfinal.plugin.activerecord.IBean; - -/** - * Generated by JPress, do not modify this file. - */ -@SuppressWarnings("serial") -public abstract class BaseJpressAddonMessage> extends JbootModel implements IBean { - - private static final long serialVersionUID = 1L; - - public void setId(java.lang.Long id) { - set("id", id); - } - - public java.lang.Long getId() { - return getLong("id"); - } - - /** - * 名字 - */ - public void setName(java.lang.String name) { - set("name", name); - } - - /** - * 名字 - */ - public java.lang.String getName() { - return getStr("name"); - } - - /** - * 电话 - */ - public void setPhone(java.lang.String phone) { - set("phone", phone); - } - - /** - * 电话 - */ - public java.lang.String getPhone() { - return getStr("phone"); - } - - /** - * 邮箱 - */ - public void setEmail(java.lang.String email) { - set("email", email); - } - - /** - * 邮箱 - */ - public java.lang.String getEmail() { - return getStr("email"); - } - - /** - * 标题 - */ - public void setTitle(java.lang.String title) { - set("title", title); - } - - /** - * 标题 - */ - public java.lang.String getTitle() { - return getStr("title"); - } - - /** - * 留言内容 - */ - public void setContent(java.lang.String content) { - set("content", content); - } - - /** - * 留言内容 - */ - public java.lang.String getContent() { - return getStr("content"); - } - - /** - * 是否展示 - */ - public void setShow(java.lang.Boolean show) { - set("show", show); - } - - /** - * 是否展示 - */ - public java.lang.Boolean getShow() { - return get("show"); - } - -} +package io.jpress.addon.message.model.base; + +import io.jboot.db.model.JbootModel; +import com.jfinal.plugin.activerecord.IBean; + +/** + * Generated by JPress, do not modify this file. + */ +@SuppressWarnings("serial") +public abstract class BaseJpressAddonMessage> extends JbootModel implements IBean { + + private static final long serialVersionUID = 1L; + + public void setId(java.lang.Long id) { + set("id", id); + } + + public java.lang.Long getId() { + return getLong("id"); + } + + /** + * 名字 + */ + public void setName(java.lang.String name) { + set("name", name); + } + + /** + * 名字 + */ + public java.lang.String getName() { + return getStr("name"); + } + + /** + * 电话 + */ + public void setPhone(java.lang.String phone) { + set("phone", phone); + } + + /** + * 电话 + */ + public java.lang.String getPhone() { + return getStr("phone"); + } + + /** + * 邮箱 + */ + public void setEmail(java.lang.String email) { + set("email", email); + } + + /** + * 邮箱 + */ + public java.lang.String getEmail() { + return getStr("email"); + } + + /** + * 标题 + */ + public void setTitle(java.lang.String title) { + set("title", title); + } + + /** + * 标题 + */ + public java.lang.String getTitle() { + return getStr("title"); + } + + /** + * 留言内容 + */ + public void setContent(java.lang.String content) { + set("content", content); + } + + /** + * 留言内容 + */ + public java.lang.String getContent() { + return getStr("content"); + } + + /** + * 是否展示 + */ + public void setShow(java.lang.Boolean show) { + set("show", show); + } + + /** + * 是否展示 + */ + public java.lang.Boolean getShow() { + return get("show"); + } + +} diff --git a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/service/JpressAddonMessageService.java b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/service/JpressAddonMessageService.java index b0c61290e9cfc66791c40c06eb5c983fed9b77d7..d5c59db153c79fd5dd6148624bc2e21e28877a69 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/service/JpressAddonMessageService.java +++ b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/service/JpressAddonMessageService.java @@ -1,178 +1,178 @@ -package io.jpress.addon.message.service; - -import com.jfinal.plugin.activerecord.Page; -import io.jpress.addon.message.model.JpressAddonMessage; -import io.jboot.db.model.Columns; - -import java.util.List; - -public interface JpressAddonMessageService { - - /** - * 根据主键查找Model - * - * @param id - * @return - */ - public JpressAddonMessage findById(Object id); - - - /** - * 根据 Columns 查找单条数据 - * - * @param columns - * @return - */ - public JpressAddonMessage findFirstByColumns(Columns columns); - - /** - * 根据 Columns 查找单条数据 - * - * @param columns - * @param orderBy - * @return - */ - public JpressAddonMessage findFirstByColumns(Columns columns, String orderBy); - - - /** - * 查找全部数据 - * - * @return - */ - public List findAll(); - - - /** - * 根据 Columns 查找数据 - * - * @param columns - * @return - */ - public List findListByColumns(Columns columns); - - - /** - * 根据 Columns 查找数据 - * - * @param columns - * @param orderBy - * @return - */ - public List findListByColumns(Columns columns, String orderBy); - - /** - * 根据 Columns 查找数据 - * - * @param columns - * @param count - * @return - */ - public List findListByColumns(Columns columns, Integer count); - - /** - * 根据 Columns 查找数据 - * - * @param columns - * @param orderBy - * @param count - * @return - */ - public List findListByColumns(Columns columns, String orderBy, Integer count); - - - /** - * 根据提交查询数据量 - * - * @param columns - * @return - */ - public long findCountByColumns(Columns columns); - - - /** - * 根据ID 删除model - * - * @param id - * @return - */ - public boolean deleteById(Object id); - - - /** - * 删除 - * - * @param model - * @return - */ - public boolean delete(JpressAddonMessage model); - - - /** - * 根据 多个 id 批量删除 - * - * @param ids - * @return - */ - public boolean batchDeleteByIds(Object... ids); - - - /** - * 保存到数据库 - * - * @param model - * @return id if success - */ - public Object save(JpressAddonMessage model); - - - /** - * 保存或更新 - * - * @param model - * @return id if success - */ - public Object saveOrUpdate(JpressAddonMessage model); - - /** - * 更新 - * - * @param model - * @return - */ - public boolean update(JpressAddonMessage model); - - - /** - * 分页 - * - * @param page - * @param pageSize - * @return - */ - public Page paginate(int page, int pageSize); - - - /** - * 分页 - * - * @param page - * @param pageSize - * @return - */ - public Page paginateByColumns(int page, int pageSize, Columns columns); - - - /** - * 分页 - * - * @param page - * @param pageSize - * @param columns - * @param orderBy - * @return - */ - public Page paginateByColumns(int page, int pageSize, Columns columns, String orderBy); - - +package io.jpress.addon.message.service; + +import com.jfinal.plugin.activerecord.Page; +import io.jpress.addon.message.model.JpressAddonMessage; +import io.jboot.db.model.Columns; + +import java.util.List; + +public interface JpressAddonMessageService { + + /** + * 根据主键查找Model + * + * @param id + * @return + */ + public JpressAddonMessage findById(Object id); + + + /** + * 根据 Columns 查找单条数据 + * + * @param columns + * @return + */ + public JpressAddonMessage findFirstByColumns(Columns columns); + + /** + * 根据 Columns 查找单条数据 + * + * @param columns + * @param orderBy + * @return + */ + public JpressAddonMessage findFirstByColumns(Columns columns, String orderBy); + + + /** + * 查找全部数据 + * + * @return + */ + public List findAll(); + + + /** + * 根据 Columns 查找数据 + * + * @param columns + * @return + */ + public List findListByColumns(Columns columns); + + + /** + * 根据 Columns 查找数据 + * + * @param columns + * @param orderBy + * @return + */ + public List findListByColumns(Columns columns, String orderBy); + + /** + * 根据 Columns 查找数据 + * + * @param columns + * @param count + * @return + */ + public List findListByColumns(Columns columns, Integer count); + + /** + * 根据 Columns 查找数据 + * + * @param columns + * @param orderBy + * @param count + * @return + */ + public List findListByColumns(Columns columns, String orderBy, Integer count); + + + /** + * 根据提交查询数据量 + * + * @param columns + * @return + */ + public long findCountByColumns(Columns columns); + + + /** + * 根据ID 删除model + * + * @param id + * @return + */ + public boolean deleteById(Object id); + + + /** + * 删除 + * + * @param model + * @return + */ + public boolean delete(JpressAddonMessage model); + + + /** + * 根据 多个 id 批量删除 + * + * @param ids + * @return + */ + public boolean batchDeleteByIds(Object... ids); + + + /** + * 保存到数据库 + * + * @param model + * @return id if success + */ + public Object save(JpressAddonMessage model); + + + /** + * 保存或更新 + * + * @param model + * @return id if success + */ + public Object saveOrUpdate(JpressAddonMessage model); + + /** + * 更新 + * + * @param model + * @return + */ + public boolean update(JpressAddonMessage model); + + + /** + * 分页 + * + * @param page + * @param pageSize + * @return + */ + public Page paginate(int page, int pageSize); + + + /** + * 分页 + * + * @param page + * @param pageSize + * @return + */ + public Page paginateByColumns(int page, int pageSize, Columns columns); + + + /** + * 分页 + * + * @param page + * @param pageSize + * @param columns + * @param orderBy + * @return + */ + public Page paginateByColumns(int page, int pageSize, Columns columns, String orderBy); + + } \ No newline at end of file diff --git a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/service/provider/JpressAddonMessageServiceProvider.java b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/service/provider/JpressAddonMessageServiceProvider.java index 343dba08a112088894ef0ccf64d4cfd61780631d..e272e75b123500d199c608169b520380293bec1b 100644 --- a/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/service/provider/JpressAddonMessageServiceProvider.java +++ b/jpress-addons/jpress-addon-message/src/main/java/io/jpress/addon/message/service/provider/JpressAddonMessageServiceProvider.java @@ -1,11 +1,11 @@ -package io.jpress.addon.message.service.provider; - -import io.jboot.aop.annotation.Bean; -import io.jpress.addon.message.service.JpressAddonMessageService; -import io.jpress.addon.message.model.JpressAddonMessage; -import io.jboot.service.JbootServiceBase; - -@Bean -public class JpressAddonMessageServiceProvider extends JbootServiceBase implements JpressAddonMessageService { - +package io.jpress.addon.message.service.provider; + +import io.jboot.aop.annotation.Bean; +import io.jpress.addon.message.service.JpressAddonMessageService; +import io.jpress.addon.message.model.JpressAddonMessage; +import io.jboot.service.JbootServiceBase; + +@Bean +public class JpressAddonMessageServiceProvider extends JbootServiceBase implements JpressAddonMessageService { + } \ No newline at end of file diff --git a/jpress-addons/jpress-addon-message/src/main/resources/addon.txt b/jpress-addons/jpress-addon-message/src/main/resources/addon.txt index b30024e76d55c3484584b22daf4be9564c8b8d5c..2323fb2d3ee3d899b3843b489b8c2005c67e40f9 100644 --- a/jpress-addons/jpress-addon-message/src/main/resources/addon.txt +++ b/jpress-addons/jpress-addon-message/src/main/resources/addon.txt @@ -1,7 +1,7 @@ -id=io.jpress.addon.message -title=留言插件 -description=JPress留言扩展功能 -author=安杰 -authorWebsite= -version=1.0.1 -versionCode=2 +id=io.jpress.addon.message +title=留言插件 +description=JPress留言扩展功能 +author=安杰 +authorWebsite= +version=1.0.1 +versionCode=2 diff --git a/jpress-addons/jpress-addon-message/src/main/resources/changelog.txt b/jpress-addons/jpress-addon-message/src/main/resources/changelog.txt index 918e0e6375d0af966bd05d9ea94b6f46b03ba4eb..579b23f323e6f8a497b6d478dc977789d9866d16 100644 --- a/jpress-addons/jpress-addon-message/src/main/resources/changelog.txt +++ b/jpress-addons/jpress-addon-message/src/main/resources/changelog.txt @@ -1 +1 @@ -# v1.0.1 修复xss漏洞 +# v1.0.1 修复xss漏洞 diff --git a/jpress-addons/jpress-addon-message/src/main/resources/readme.txt b/jpress-addons/jpress-addon-message/src/main/resources/readme.txt index 398f657e9df2a8c74c24670c95530bf94abe9024..547020c66f75c6fc7009c12fe1092f47cf276546 100644 --- a/jpress-addons/jpress-addon-message/src/main/resources/readme.txt +++ b/jpress-addons/jpress-addon-message/src/main/resources/readme.txt @@ -1,27 +1,27 @@ -用于jpress的拓展插件主要实现了用户提交留言的功能 - -代码示例:获取用户留言的列表 -``` -#messageList() -#for(msg : messageList) -

    -
    -
    -
    -
    #(msg.name ??)
    - -
    -
    -

    #(msg.message ??)

    -
    -
    -
    -
    -#end -#end -``` -提交留言接口地址: /msgController - - -![输入图片说明](https://images.gitee.com/uploads/images/2020/0226/214527_cc2a8636_2147597.png) +用于jpress的拓展插件主要实现了用户提交留言的功能 + +代码示例:获取用户留言的列表 +``` +#messageList() +#for(msg : messageList) +
    +
    +
    +
    +
    #(msg.name ??)
    + +
    +
    +

    #(msg.message ??)

    +
    +
    +
    +
    +#end +#end +``` +提交留言接口地址: /msgController + + +![输入图片说明](https://images.gitee.com/uploads/images/2020/0226/214527_cc2a8636_2147597.png) ![输入图片说明](https://images.gitee.com/uploads/images/2020/0226/214555_963e756a_2147597.png) \ No newline at end of file diff --git a/jpress-addons/jpress-addon-message/src/main/resources/sql/install.sql b/jpress-addons/jpress-addon-message/src/main/resources/sql/install.sql index 50cecfb63952b36ae4603b72139bad1f9ed9876f..363cdc402c5119c87153b42dc21f9c55ed70308b 100644 --- a/jpress-addons/jpress-addon-message/src/main/resources/sql/install.sql +++ b/jpress-addons/jpress-addon-message/src/main/resources/sql/install.sql @@ -1,11 +1,11 @@ -DROP TABLE IF EXISTS `jpress_addon_message`; -CREATE TABLE `jpress_addon_message` ( - `id` int(11) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '名字', - `phone` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '电话', - `email` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '邮箱', - `title` varchar(255) DEFAULT NULL COMMENT '标题', - `content` text CHARACTER SET utf8 COMMENT '留言内容', - `show` tinyint(1) DEFAULT NULL COMMENT '是否展示', - PRIMARY KEY (`id`) +DROP TABLE IF EXISTS `jpress_addon_message`; +CREATE TABLE `jpress_addon_message` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '名字', + `phone` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '电话', + `email` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '邮箱', + `title` varchar(255) DEFAULT NULL COMMENT '标题', + `content` text CHARACTER SET utf8 COMMENT '留言内容', + `show` tinyint(1) DEFAULT NULL COMMENT '是否展示', + PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/jpress-addons/jpress-addon-message/src/main/resources/sql/uninstall.sql b/jpress-addons/jpress-addon-message/src/main/resources/sql/uninstall.sql index 0214b333d13d061b32114b0ee0817ee5cab93fa7..e479b5a52743bc5d34b794328d41fb594ef3259b 100644 --- a/jpress-addons/jpress-addon-message/src/main/resources/sql/uninstall.sql +++ b/jpress-addons/jpress-addon-message/src/main/resources/sql/uninstall.sql @@ -1 +1 @@ -DROP TABLE IF EXISTS `jpress_addon_message` +DROP TABLE IF EXISTS `jpress_addon_message` diff --git a/jpress-addons/jpress-addon-message/src/main/webapp/views/jpress_addon_message_edit.html b/jpress-addons/jpress-addon-message/src/main/webapp/views/jpress_addon_message_edit.html index 4441e0056b06e74a4201553c56ebf21d97e4d0b5..7b7c6b366ba83da76c1c0b9701600e61e54d7b2a 100644 --- a/jpress-addons/jpress-addon-message/src/main/webapp/views/jpress_addon_message_edit.html +++ b/jpress-addons/jpress-addon-message/src/main/webapp/views/jpress_addon_message_edit.html @@ -1,124 +1,124 @@ - -#@layout() -#define css() -#@layout_css?() - -#end -#define script() -#@layout_script?() - - - -#end - - -#define content() -
    - -
    -

    - 编辑/新增 - Edit -

    -
    - -
    - -
    -
    -
    -
    -

    -
    -
    - -
    - -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    - -
    - -
    - - -
    -
    - -
    - -
    - - -
    -
    -
    - -
    - - - -
    -
    - -
    - - - -
    -
    -
    -
    - -
    - -
    + +#@layout() +#define css() +#@layout_css?() + +#end +#define script() +#@layout_script?() + + + +#end + + +#define content() +
    + +
    +

    + 编辑/新增 + Edit +

    +
    + +
    + +
    +
    +
    +
    +

    +
    +
    + +
    + +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + +
    +
    +
    + +
    + + + +
    +
    + +
    + + + +
    +
    +
    +
    + +
    + +
    #end \ No newline at end of file diff --git a/jpress-addons/jpress-addon-message/src/main/webapp/views/jpress_addon_message_list.html b/jpress-addons/jpress-addon-message/src/main/webapp/views/jpress_addon_message_list.html index 4b145b891d85c2c59ec8354556cbabeda4e20c0f..8d7d360f33b88e59493e967293b4087f91a1744d 100644 --- a/jpress-addons/jpress-addon-message/src/main/webapp/views/jpress_addon_message_list.html +++ b/jpress-addons/jpress-addon-message/src/main/webapp/views/jpress_addon_message_list.html @@ -1,110 +1,110 @@ -#@layout() - -#define script() - -#end - -#define content() -
    - -
    -

    - 管理 - Items -

    -
    - -
    - -
    -
    -
    -
    - -
    -
    - - 新建 - - -
    -
    - -
    - -
    - - - - - - - - - - - - - - - #for(entry : page.list) - - - - - - - - - - - - #end - -
    - - 名字电话邮箱标题留言是否展示
    -
    - - -
    - -
    -
    - -
    -
    -#end +#@layout() + +#define script() + +#end + +#define content() +
    + +
    +

    + 管理 + Items +

    +
    + +
    + +
    +
    +
    +
    + +
    +
    + + 新建 + + +
    +
    + +
    + +
    + + + + + + + + + + + + + + + #for(entry : page.list) + + + + + + + + + + + + #end + +
    + + 名字电话邮箱标题留言是否展示
    +
    + + +
    + +
    +
    + +
    +
    +#end diff --git a/jpress-addons/pom.xml b/jpress-addons/pom.xml index d5a0363634d52abe1c0f9304d44cf31065f3c7da..9656088687a3e1fa13c6af342c110fb86a9868e7 100644 --- a/jpress-addons/pom.xml +++ b/jpress-addons/pom.xml @@ -1,48 +1,48 @@ - - - - parent - io.jpress - 3.0 - - 4.0.0 - pom - 3.0 - - io.jpress - jpress-addons - - - 1.8 - 1.8 - - - - jpress-addon-helloworld - jpress-addon-message - - - - - - - - - - - - - - org.codehaus.mojo - versions-maven-plugin - 2.7 - - false - - - - - - + + + + parent + io.jpress + 3.0 + + 4.0.0 + pom + 3.0 + + io.jpress + jpress-addons + + + 1.8 + 1.8 + + + + jpress-addon-helloworld + jpress-addon-message + + + + + + + + + + + + + + org.codehaus.mojo + versions-maven-plugin + 2.7 + + false + + + + + + diff --git a/jpress-commons/pom.xml b/jpress-commons/pom.xml index 2722c4b5dcfe10462ff8e16495d19ea07c840f6b..2dc3cc95a4aff80a9f00ec360d40f31b1af6b051 100644 --- a/jpress-commons/pom.xml +++ b/jpress-commons/pom.xml @@ -1,96 +1,96 @@ - - - - io.jpress - parent - 3.0 - - - 4.0.0 - - io.jpress - jpress-commons - - - - - io.jboot - jboot - - - - commons-io - commons-io - - - - com.aliyun.oss - aliyun-sdk-oss - - - - org.apache.httpcomponents - httpclient - - - - commons-codec - commons-codec - - - - javax.mail - javax.mail-api - - - - com.sun.mail - javax.mail - - - - com.atlassian.commonmark - commonmark - - - - com.atlassian.commonmark - commonmark-ext-gfm-tables - - - - com.atlassian.commonmark - commonmark-ext-yaml-front-matter - - - - com.egzosn - pay-java-ali - - - - com.egzosn - pay-java-paypal - - - - com.egzosn - pay-java-wx - - - - com.github.houbb - opencc4j - 1.4.0 - - - - com.github.promeg - tinypinyin - 2.0.3 - - - + + + + io.jpress + parent + 3.0 + + + 4.0.0 + + io.jpress + jpress-commons + + + + + io.jboot + jboot + + + + commons-io + commons-io + + + + com.aliyun.oss + aliyun-sdk-oss + + + + org.apache.httpcomponents + httpclient + + + + commons-codec + commons-codec + + + + javax.mail + javax.mail-api + + + + com.sun.mail + javax.mail + + + + com.atlassian.commonmark + commonmark + + + + com.atlassian.commonmark + commonmark-ext-gfm-tables + + + + com.atlassian.commonmark + commonmark-ext-yaml-front-matter + + + + com.egzosn + pay-java-ali + + + + com.egzosn + pay-java-paypal + + + + com.egzosn + pay-java-wx + + + + com.github.houbb + opencc4j + 1.4.0 + + + + com.github.promeg + tinypinyin + 2.0.3 + + + \ No newline at end of file diff --git a/jpress-commons/src/main/java/io/jpress/JPressActiveKit.java b/jpress-commons/src/main/java/io/jpress/JPressActiveKit.java index 858371381dcce831d1a9faf4fd57ee9c056cd4c4..65a62891bac5afe6068c8287c2dbb0075519cd36 100644 --- a/jpress-commons/src/main/java/io/jpress/JPressActiveKit.java +++ b/jpress-commons/src/main/java/io/jpress/JPressActiveKit.java @@ -1,48 +1,48 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress; - -import com.jfinal.plugin.activerecord.Model; -import io.jpress.commons.layer.SortModel; - - -public class JPressActiveKit { - - /** - * 用于标识当前 是否选中 - */ - public static final String ACTIVE_FLAG = "isActive"; - - /** - * 标识当前对象(一般情况下是分类、菜单等) - * - * @param model - */ - public static void makeItActive(Model model) { - - model.put(ACTIVE_FLAG, true); - - if (model instanceof SortModel) { - SortModel parent = ((SortModel) model).getParent(); - //理论上,parent == model 这种情况不可能存在, - //目前只是为了防止万一哪个兔崽子的代码有问题,从而会出现死循环 - if (parent != null && parent != model) { - makeItActive((Model) parent); - } - } - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress; + +import com.jfinal.plugin.activerecord.Model; +import io.jpress.commons.layer.SortModel; + + +public class JPressActiveKit { + + /** + * 用于标识当前 是否选中 + */ + public static final String ACTIVE_FLAG = "isActive"; + + /** + * 标识当前对象(一般情况下是分类、菜单等) + * + * @param model + */ + public static void makeItActive(Model model) { + + model.put(ACTIVE_FLAG, true); + + if (model instanceof SortModel) { + SortModel parent = ((SortModel) model).getParent(); + //理论上,parent == model 这种情况不可能存在, + //目前只是为了防止万一哪个兔崽子的代码有问题,从而会出现死循环 + if (parent != null && parent != model) { + makeItActive((Model) parent); + } + } + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/JPressConfig.java b/jpress-commons/src/main/java/io/jpress/JPressConfig.java index 54c7bc5e02b6d1dd0d433e2b272b9a7e7279da95..086d6408d8baa7a95c3e27faf145a635a3621cf0 100644 --- a/jpress-commons/src/main/java/io/jpress/JPressConfig.java +++ b/jpress-commons/src/main/java/io/jpress/JPressConfig.java @@ -1,159 +1,159 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

    - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

    - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *

    - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress; - -import com.jfinal.kit.PathKit; -import io.jboot.Jboot; -import io.jboot.app.config.annotation.ConfigModel; -import io.jboot.utils.StrUtil; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 环境配置 - * @Package io.jpress - */ -@ConfigModel(prefix = "jpress") -public class JPressConfig { - - public static final String DEFAULT_LOGIN_PAGE = "/admin/login"; - - private String indexAction = "/page"; - private String defaultTemplate = "cn.jeanstudio.bonhumeur"; - private String attachmentRoot; // attachment 目录,在未配置的情况下,在 webapp 目录下 - private String adminLoginPage = DEFAULT_LOGIN_PAGE; //登录的页面 - private String adminLoginAction = "/admin/doLogin"; //登录的方法 - - /** - * 是否开启模板预览的功能 - */ - private boolean templatePreviewEnable = false; - - - public String getIndexAction() { - return indexAction; - } - - public void setIndexAction(String indexAction) { - this.indexAction = indexAction; - } - - public String getDefaultTemplate() { - return defaultTemplate; - } - - public void setDefaultTemplate(String defaultTemplate) { - this.defaultTemplate = defaultTemplate; - } - - - public String getAttachmentRoot() { - return attachmentRoot; - } - - public void setAttachmentRoot(String attachmentRoot) { - this.attachmentRoot = attachmentRoot; - } - - public String getAdminLoginPage() { - return adminLoginPage; - } - - public void setAdminLoginPage(String adminLoginPage) { - this.adminLoginPage = adminLoginPage; - } - - public String getAdminLoginAction() { - return adminLoginAction; - } - - public void setAdminLoginAction(String adminLoginAction) { - this.adminLoginAction = adminLoginAction; - } - - public boolean isTemplatePreviewEnable() { - return templatePreviewEnable; - } - - public void setTemplatePreviewEnable(boolean templatePreviewEnable) { - this.templatePreviewEnable = templatePreviewEnable; - } - - public String getAttachmentRootOrWebRoot() { - return StrUtil.isNotBlank(attachmentRoot) - ? attachmentRoot - : PathKit.getWebRootPath(); - } - - public static final JPressConfig me = Jboot.config(JPressConfig.class); -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *

    + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *

    + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *

    + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress; + +import com.jfinal.kit.PathKit; +import io.jboot.Jboot; +import io.jboot.app.config.annotation.ConfigModel; +import io.jboot.utils.StrUtil; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 环境配置 + * @Package io.jpress + */ +@ConfigModel(prefix = "jpress") +public class JPressConfig { + + public static final String DEFAULT_LOGIN_PAGE = "/admin/login"; + + private String indexAction = "/page"; + private String defaultTemplate = "cn.jeanstudio.bonhumeur"; + private String attachmentRoot; // attachment 目录,在未配置的情况下,在 webapp 目录下 + private String adminLoginPage = DEFAULT_LOGIN_PAGE; //登录的页面 + private String adminLoginAction = "/admin/doLogin"; //登录的方法 + + /** + * 是否开启模板预览的功能 + */ + private boolean templatePreviewEnable = false; + + + public String getIndexAction() { + return indexAction; + } + + public void setIndexAction(String indexAction) { + this.indexAction = indexAction; + } + + public String getDefaultTemplate() { + return defaultTemplate; + } + + public void setDefaultTemplate(String defaultTemplate) { + this.defaultTemplate = defaultTemplate; + } + + + public String getAttachmentRoot() { + return attachmentRoot; + } + + public void setAttachmentRoot(String attachmentRoot) { + this.attachmentRoot = attachmentRoot; + } + + public String getAdminLoginPage() { + return adminLoginPage; + } + + public void setAdminLoginPage(String adminLoginPage) { + this.adminLoginPage = adminLoginPage; + } + + public String getAdminLoginAction() { + return adminLoginAction; + } + + public void setAdminLoginAction(String adminLoginAction) { + this.adminLoginAction = adminLoginAction; + } + + public boolean isTemplatePreviewEnable() { + return templatePreviewEnable; + } + + public void setTemplatePreviewEnable(boolean templatePreviewEnable) { + this.templatePreviewEnable = templatePreviewEnable; + } + + public String getAttachmentRootOrWebRoot() { + return StrUtil.isNotBlank(attachmentRoot) + ? attachmentRoot + : PathKit.getWebRootPath(); + } + + public static final JPressConfig me = Jboot.config(JPressConfig.class); +} diff --git a/jpress-commons/src/main/java/io/jpress/JPressConsts.java b/jpress-commons/src/main/java/io/jpress/JPressConsts.java index 2f7975895506ddf4dc204989c87d57403891b562..ed12b263fb81abcda871c57959c55a6f57d8fb76 100644 --- a/jpress-commons/src/main/java/io/jpress/JPressConsts.java +++ b/jpress-commons/src/main/java/io/jpress/JPressConsts.java @@ -1,128 +1,128 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 常量 - * @Package io.jpress - */ -public class JPressConsts { - - public static final String VERSION = "v3.2.3"; - public static final String VERSION_CODE = "23"; - - /** - * 后台系统菜单的 ID - */ - public static final String SYSTEM_MENU_USER = "user"; - public static final String SYSTEM_MENU_ATTACHMENT = "attachment"; - public static final String SYSTEM_MENU_TEMPLATE = "template"; - public static final String SYSTEM_MENU_ADDON = "addon"; - public static final String SYSTEM_MENU_SYSTEM = "system"; - public static final String SYSTEM_MENU_ORDER = "order"; - public static final String SYSTEM_MENU_FINANCE = "finance"; - public static final String SYSTEM_MENU_WECHAT_PUBULIC_ACCOUNT = "wechat_pubulic_account"; - public static final String SYSTEM_MENU_WECHAT_MINI_PROGRAM = "wechat_mini_program"; - - - /** - * 以下是配置相关 - */ - public static final String OPTION_WEB_TITLE = "web_title"; //网站标题 - public static final String OPTION_WEB_SUBTITLE = "web_subtitle"; // 网站副标题 - public static final String OPTION_WEB_NAME = "web_name"; // 网站名称 - public static final String OPTION_WEB_DOMAIN = "web_domain"; // 网站域名 - public static final String OPTION_WEB_COPYRIGHT = "web_copyright"; // 网站版权信息 - public static final String OPTION_WEB_IPC_NO = "web_ipc_no"; // 网站备案号 - public static final String OPTION_SEO_TITLE = "seo_title"; // SEO 标题 - public static final String OPTION_SEO_KEYWORDS = "seo_keywords"; // SEO 关键字 - public static final String OPTION_SEO_DESCRIPTION = "seo_description"; // SEO 描述 - - - public static final String OPTION_WEB_FAKE_STATIC_ENABLE = "web_fake_static_enable"; //是否启用伪静态 - public static final String OPTION_WEB_FAKE_STATIC_SUFFIX = "web_fake_static_suffix"; //网站伪静态后缀 - - public static final String OPTION_CDN_ENABLE = "cdn_enable"; //是否启用CDN - public static final String OPTION_CDN_DOMAIN = "cdn_domain"; //CDN域名 - - public static final String OPTION_API_ENABLE = "api_enable"; //是否启用API - public static final String OPTION_API_SECRET = "api_secret"; //API密钥 - public static final String OPTION_API_APPID = "api_app_id"; //API应用ID - - public static final String OPTION_WECHAT_WEB_AUTHORIZE_ENABLE = "wechat_web_authorize_enable"; //是否启用微信网页授权功能 - - - public static final String OPTION_WECHAT_APPID = "wechat_appid"; //微信的APP Id - public static final String OPTION_WECHAT_APPSECRET = "wechat_appsecret"; //微信的 APP Secret - public static final String OPTION_WECHAT_TOKEN = "wechat_token"; //微信的 token - - public static final String OPTION_WECHAT_MINIPROGRAM_APPID = "wechat_miniprogram_appid"; //微信小程序的 token - public static final String OPTION_WECHAT_MINIPROGRAM_APPSECRET = "wechat_miniprogram_appsecret"; //微信小程序的 token - public static final String OPTION_WECHAT_MINIPROGRAM_TOKEN = "wechat_miniprogram_token"; //微信小程序的 token - - - public static final String OPTION_CONNECTION_EMAIL_ENABLE = "connection_email_enable"; // 是否启用邮件发送功能 - public static final String OPTION_CONNECTION_EMAIL_SMTP = "connection_email_smtp"; // 邮件服务器smtp - public static final String OPTION_CONNECTION_EMAIL_ACCOUNT = "connection_email_account"; //邮箱账号 - public static final String OPTION_CONNECTION_EMAIL_PASSWORD = "connection_email_password"; //邮箱密码 - public static final String OPTION_CONNECTION_EMAIL_SSL_ENABLE = "connection_email_ssl_enable"; //是否启用ssl - - - public static final String OPTION_CONNECTION_SMS_ENABLE = "connection_sms_enable"; //是否启用短信 - public static final String OPTION_CONNECTION_SMS_TYPE = "connection_sms_type"; //短信服务商 - public static final String OPTION_CONNECTION_SMS_APPID = "connection_sms_appid"; // 服务商 的appid(或者appKey) - public static final String OPTION_CONNECTION_SMS_APPSECRET = "connection_sms_appsecret"; //app密钥 - - - public static final String SMS_TYPE_ALIYUN = "aliyun"; //短信服务商:阿里云 - public static final String SMS_TYPE_QCLOUD = "qcloud"; //短信服务商:腾讯云 - - /** - * 用到的cookie name 常量 - */ - public static final String COOKIE_UID = "_jpuid"; - public static final String COOKIE_ANONYM = "_jpanonym"; - public static final String COOKIE_EDIT_MODE = "_jpeditmode"; - - /** - * 用到的request attribute常量 - */ - public static final String ATTR_LOGINED_USER = "USER"; - - - public static final String ATTR_WEB_TITLE = "WEB_TITLE"; //网站标题 - public static final String ATTR_WEB_SUBTITLE = "WEB_SUBTITLE"; // 网站副标题 - public static final String ATTR_WEB_NAME = "WEB_NAME"; // 网站名称 - public static final String ATTR_WEB_DOMAIN = "WEB_DOMAIN"; // 网站域名 - public static final String ATTR_WEB_COPYRIGHT = "WEB_COPYRIGHT"; // 网站版权信息 - public static final String ATTR_WEB_IPC_NO = "WEB_IPC_NO"; // 网站备案号 - public static final String ATTR_SEO_TITLE = "SEO_TITLE"; // SEO 标题 - public static final String ATTR_SEO_KEYWORDS = "SEO_KEYWORDS"; // SEO 关键字 - public static final String ATTR_SEO_DESCRIPTION = "SEO_DESCRIPTION"; // SEO 描述 - - public static final String ATTR_MENUS = "MENUS"; // 页面菜单 - - public static final String EDIT_MODE_HTML = "html"; //html 的编辑模式 - public static final String EDIT_MODE_MARKDOWN = "markdown"; //markdown 的编辑模式 - - - public static final String JWT_USERID = "userId"; - - - public static final String DEFAULT_ADMIN_VIEW = "/WEB-INF/views/admin/"; -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 常量 + * @Package io.jpress + */ +public class JPressConsts { + + public static final String VERSION = "v3.2.3"; + public static final String VERSION_CODE = "23"; + + /** + * 后台系统菜单的 ID + */ + public static final String SYSTEM_MENU_USER = "user"; + public static final String SYSTEM_MENU_ATTACHMENT = "attachment"; + public static final String SYSTEM_MENU_TEMPLATE = "template"; + public static final String SYSTEM_MENU_ADDON = "addon"; + public static final String SYSTEM_MENU_SYSTEM = "system"; + public static final String SYSTEM_MENU_ORDER = "order"; + public static final String SYSTEM_MENU_FINANCE = "finance"; + public static final String SYSTEM_MENU_WECHAT_PUBULIC_ACCOUNT = "wechat_pubulic_account"; + public static final String SYSTEM_MENU_WECHAT_MINI_PROGRAM = "wechat_mini_program"; + + + /** + * 以下是配置相关 + */ + public static final String OPTION_WEB_TITLE = "web_title"; //网站标题 + public static final String OPTION_WEB_SUBTITLE = "web_subtitle"; // 网站副标题 + public static final String OPTION_WEB_NAME = "web_name"; // 网站名称 + public static final String OPTION_WEB_DOMAIN = "web_domain"; // 网站域名 + public static final String OPTION_WEB_COPYRIGHT = "web_copyright"; // 网站版权信息 + public static final String OPTION_WEB_IPC_NO = "web_ipc_no"; // 网站备案号 + public static final String OPTION_SEO_TITLE = "seo_title"; // SEO 标题 + public static final String OPTION_SEO_KEYWORDS = "seo_keywords"; // SEO 关键字 + public static final String OPTION_SEO_DESCRIPTION = "seo_description"; // SEO 描述 + + + public static final String OPTION_WEB_FAKE_STATIC_ENABLE = "web_fake_static_enable"; //是否启用伪静态 + public static final String OPTION_WEB_FAKE_STATIC_SUFFIX = "web_fake_static_suffix"; //网站伪静态后缀 + + public static final String OPTION_CDN_ENABLE = "cdn_enable"; //是否启用CDN + public static final String OPTION_CDN_DOMAIN = "cdn_domain"; //CDN域名 + + public static final String OPTION_API_ENABLE = "api_enable"; //是否启用API + public static final String OPTION_API_SECRET = "api_secret"; //API密钥 + public static final String OPTION_API_APPID = "api_app_id"; //API应用ID + + public static final String OPTION_WECHAT_WEB_AUTHORIZE_ENABLE = "wechat_web_authorize_enable"; //是否启用微信网页授权功能 + + + public static final String OPTION_WECHAT_APPID = "wechat_appid"; //微信的APP Id + public static final String OPTION_WECHAT_APPSECRET = "wechat_appsecret"; //微信的 APP Secret + public static final String OPTION_WECHAT_TOKEN = "wechat_token"; //微信的 token + + public static final String OPTION_WECHAT_MINIPROGRAM_APPID = "wechat_miniprogram_appid"; //微信小程序的 token + public static final String OPTION_WECHAT_MINIPROGRAM_APPSECRET = "wechat_miniprogram_appsecret"; //微信小程序的 token + public static final String OPTION_WECHAT_MINIPROGRAM_TOKEN = "wechat_miniprogram_token"; //微信小程序的 token + + + public static final String OPTION_CONNECTION_EMAIL_ENABLE = "connection_email_enable"; // 是否启用邮件发送功能 + public static final String OPTION_CONNECTION_EMAIL_SMTP = "connection_email_smtp"; // 邮件服务器smtp + public static final String OPTION_CONNECTION_EMAIL_ACCOUNT = "connection_email_account"; //邮箱账号 + public static final String OPTION_CONNECTION_EMAIL_PASSWORD = "connection_email_password"; //邮箱密码 + public static final String OPTION_CONNECTION_EMAIL_SSL_ENABLE = "connection_email_ssl_enable"; //是否启用ssl + + + public static final String OPTION_CONNECTION_SMS_ENABLE = "connection_sms_enable"; //是否启用短信 + public static final String OPTION_CONNECTION_SMS_TYPE = "connection_sms_type"; //短信服务商 + public static final String OPTION_CONNECTION_SMS_APPID = "connection_sms_appid"; // 服务商 的appid(或者appKey) + public static final String OPTION_CONNECTION_SMS_APPSECRET = "connection_sms_appsecret"; //app密钥 + + + public static final String SMS_TYPE_ALIYUN = "aliyun"; //短信服务商:阿里云 + public static final String SMS_TYPE_QCLOUD = "qcloud"; //短信服务商:腾讯云 + + /** + * 用到的cookie name 常量 + */ + public static final String COOKIE_UID = "_jpuid"; + public static final String COOKIE_ANONYM = "_jpanonym"; + public static final String COOKIE_EDIT_MODE = "_jpeditmode"; + + /** + * 用到的request attribute常量 + */ + public static final String ATTR_LOGINED_USER = "USER"; + + + public static final String ATTR_WEB_TITLE = "WEB_TITLE"; //网站标题 + public static final String ATTR_WEB_SUBTITLE = "WEB_SUBTITLE"; // 网站副标题 + public static final String ATTR_WEB_NAME = "WEB_NAME"; // 网站名称 + public static final String ATTR_WEB_DOMAIN = "WEB_DOMAIN"; // 网站域名 + public static final String ATTR_WEB_COPYRIGHT = "WEB_COPYRIGHT"; // 网站版权信息 + public static final String ATTR_WEB_IPC_NO = "WEB_IPC_NO"; // 网站备案号 + public static final String ATTR_SEO_TITLE = "SEO_TITLE"; // SEO 标题 + public static final String ATTR_SEO_KEYWORDS = "SEO_KEYWORDS"; // SEO 关键字 + public static final String ATTR_SEO_DESCRIPTION = "SEO_DESCRIPTION"; // SEO 描述 + + public static final String ATTR_MENUS = "MENUS"; // 页面菜单 + + public static final String EDIT_MODE_HTML = "html"; //html 的编辑模式 + public static final String EDIT_MODE_MARKDOWN = "markdown"; //markdown 的编辑模式 + + + public static final String JWT_USERID = "userId"; + + + public static final String DEFAULT_ADMIN_VIEW = "/WEB-INF/views/admin/"; +} diff --git a/jpress-commons/src/main/java/io/jpress/JPressOptions.java b/jpress-commons/src/main/java/io/jpress/JPressOptions.java index f2b72ab02bc47436010f04be1508cd51e1502e21..73f39e282e5c4db78dcf6a1cdf14d5c1cc30d14e 100644 --- a/jpress-commons/src/main/java/io/jpress/JPressOptions.java +++ b/jpress-commons/src/main/java/io/jpress/JPressOptions.java @@ -1,234 +1,234 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress; - -import com.jfinal.log.Log; -import io.jboot.utils.StrUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @Title: JPress 配置 - */ -public class JPressOptions { - - private static final Log LOG = Log.getLog(JPressOptions.class); - - private static OptionStore store = OptionStore.defaultOptionStore; - private static List listeners = new ArrayList<>(); - - public static void set(String key, String value) { - if (StrUtil.isBlank(key)) { - return; - } - - key = key.toLowerCase(); - - String oldValue = store.get(key); - if (Objects.equals(value, oldValue)) { - return; - } - - store.put(key, value); - - - for (OptionChangeListener listener : listeners) { - try { - listener.onChanged(key, value, oldValue); - } catch (Throwable ex) { - LOG.error(ex.toString(), ex); - } - } - - doFinishedChanged(key, value, oldValue); - } - - - public static String get(String key) { - return store.get(key.toLowerCase()); - } - - - public static String get(String key, String defaultvalue) { - String v = get(key); - return StrUtil.isBlank(v) ? defaultvalue : v; - } - - public static boolean getAsBool(String key) { - return getAsBool(key,false); - } - - public static boolean getAsBool(String key, boolean defaultValue) { - String value = get(key); - return StrUtil.isBlank(value) ? defaultValue : Boolean.parseBoolean(value); - } - - @Deprecated - public static boolean isTrueOrEmpty(String key) { - return getAsBool(key, true); - } - - public static Integer getAsInt(String key) { - String value = get(key); - return StrUtil.isBlank(value) ? null : Integer.parseInt(value); - } - - - public static int getAsInt(String key, int defaultValue) { - String value = get(key); - if (StrUtil.isBlank(value)) { - return defaultValue; - } - try { - return Integer.parseInt(value); - } catch (Exception ex) { - LOG.warn(ex.toString(), ex); - return defaultValue; - } - } - - - public static Float getAsFloat(String key) { - String value = get(key); - return StrUtil.isBlank(value) ? null : Float.parseFloat(value); - } - - public static float getAsFloat(String key, float defaultValue) { - String value = get(key); - if (StrUtil.isBlank(value)) { - return defaultValue; - } - try { - return Float.parseFloat(value); - } catch (Exception ex) { - LOG.warn(ex.toString(), ex); - return defaultValue; - } - } - - public static void addListener(OptionChangeListener listener) { - listeners.add(listener); - } - - public static void removeListener(OptionChangeListener listener) { - listeners.remove(listener); - } - - - public static String getCDNDomain() { - boolean cdnEnable = getAsBool(JPressConsts.OPTION_CDN_ENABLE); - if (cdnEnable == false) { - return StrUtil.EMPTY; - } - - return get(JPressConsts.OPTION_CDN_DOMAIN, StrUtil.EMPTY); - } - - public static String getResDomain() { - String cdnDomain = getCDNDomain(); - return cdnDomain == null ? get(JPressConsts.OPTION_WEB_DOMAIN) : cdnDomain; - } - - public static interface OptionChangeListener { - public void onChanged(String key, String newValue, String oldValue); - } - - - private static final String indexStyleKey = "index_style"; - - private static void doFinishedChanged(String key, String value, String oldValue) { - if (indexStyleKey.equals(key)) { - indexStyleValue = value; - } - - //伪静态的是否启用 - else if (JPressConsts.OPTION_WEB_FAKE_STATIC_ENABLE.equals(key)) { - fakeStaticEnable = "true".equalsIgnoreCase(value); - } - - //伪静态后缀 - else if (JPressConsts.OPTION_WEB_FAKE_STATIC_SUFFIX.equals(key)) { - fakeStaticSuffix = value; - } - } - - private static String indexStyleValue = null; - - public static String getIndexStyle() { - return indexStyleValue; - } - - - private static boolean fakeStaticEnable = false; - private static String fakeStaticSuffix = ""; - - public static String getAppUrlSuffix() { - if (!fakeStaticEnable || StrUtil.isBlank(fakeStaticSuffix)) { - return ""; - } - - return fakeStaticSuffix; - } - - public static OptionStore getStore() { - return store; - } - - public static void setStore(OptionStore store) { - JPressOptions.store = store; - } - - public static interface OptionStore { - - public String get(String key); - - public void put(String key, String value); - - public void remove(String key); - - public static final OptionStore defaultOptionStore = new OptionStore() { - - private final Map cache = new ConcurrentHashMap<>(); - - @Override - public String get(String key) { - return cache.get(key); - } - - @Override - public void put(String key, String value) { - if (StrUtil.isBlank(value)) { - remove(key); - } else { - cache.put(key, value); - } - } - - @Override - public void remove(String key) { - cache.remove(key); - } - }; - - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress; + +import com.jfinal.log.Log; +import io.jboot.utils.StrUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @Title: JPress 配置 + */ +public class JPressOptions { + + private static final Log LOG = Log.getLog(JPressOptions.class); + + private static OptionStore store = OptionStore.defaultOptionStore; + private static List listeners = new ArrayList<>(); + + public static void set(String key, String value) { + if (StrUtil.isBlank(key)) { + return; + } + + key = key.toLowerCase(); + + String oldValue = store.get(key); + if (Objects.equals(value, oldValue)) { + return; + } + + store.put(key, value); + + + for (OptionChangeListener listener : listeners) { + try { + listener.onChanged(key, value, oldValue); + } catch (Throwable ex) { + LOG.error(ex.toString(), ex); + } + } + + doFinishedChanged(key, value, oldValue); + } + + + public static String get(String key) { + return store.get(key.toLowerCase()); + } + + + public static String get(String key, String defaultvalue) { + String v = get(key); + return StrUtil.isBlank(v) ? defaultvalue : v; + } + + public static boolean getAsBool(String key) { + return getAsBool(key,false); + } + + public static boolean getAsBool(String key, boolean defaultValue) { + String value = get(key); + return StrUtil.isBlank(value) ? defaultValue : Boolean.parseBoolean(value); + } + + @Deprecated + public static boolean isTrueOrEmpty(String key) { + return getAsBool(key, true); + } + + public static Integer getAsInt(String key) { + String value = get(key); + return StrUtil.isBlank(value) ? null : Integer.parseInt(value); + } + + + public static int getAsInt(String key, int defaultValue) { + String value = get(key); + if (StrUtil.isBlank(value)) { + return defaultValue; + } + try { + return Integer.parseInt(value); + } catch (Exception ex) { + LOG.warn(ex.toString(), ex); + return defaultValue; + } + } + + + public static Float getAsFloat(String key) { + String value = get(key); + return StrUtil.isBlank(value) ? null : Float.parseFloat(value); + } + + public static float getAsFloat(String key, float defaultValue) { + String value = get(key); + if (StrUtil.isBlank(value)) { + return defaultValue; + } + try { + return Float.parseFloat(value); + } catch (Exception ex) { + LOG.warn(ex.toString(), ex); + return defaultValue; + } + } + + public static void addListener(OptionChangeListener listener) { + listeners.add(listener); + } + + public static void removeListener(OptionChangeListener listener) { + listeners.remove(listener); + } + + + public static String getCDNDomain() { + boolean cdnEnable = getAsBool(JPressConsts.OPTION_CDN_ENABLE); + if (cdnEnable == false) { + return StrUtil.EMPTY; + } + + return get(JPressConsts.OPTION_CDN_DOMAIN, StrUtil.EMPTY); + } + + public static String getResDomain() { + String cdnDomain = getCDNDomain(); + return cdnDomain == null ? get(JPressConsts.OPTION_WEB_DOMAIN) : cdnDomain; + } + + public static interface OptionChangeListener { + public void onChanged(String key, String newValue, String oldValue); + } + + + private static final String indexStyleKey = "index_style"; + + private static void doFinishedChanged(String key, String value, String oldValue) { + if (indexStyleKey.equals(key)) { + indexStyleValue = value; + } + + //伪静态的是否启用 + else if (JPressConsts.OPTION_WEB_FAKE_STATIC_ENABLE.equals(key)) { + fakeStaticEnable = "true".equalsIgnoreCase(value); + } + + //伪静态后缀 + else if (JPressConsts.OPTION_WEB_FAKE_STATIC_SUFFIX.equals(key)) { + fakeStaticSuffix = value; + } + } + + private static String indexStyleValue = null; + + public static String getIndexStyle() { + return indexStyleValue; + } + + + private static boolean fakeStaticEnable = false; + private static String fakeStaticSuffix = ""; + + public static String getAppUrlSuffix() { + if (!fakeStaticEnable || StrUtil.isBlank(fakeStaticSuffix)) { + return ""; + } + + return fakeStaticSuffix; + } + + public static OptionStore getStore() { + return store; + } + + public static void setStore(OptionStore store) { + JPressOptions.store = store; + } + + public static interface OptionStore { + + public String get(String key); + + public void put(String key, String value); + + public void remove(String key); + + public static final OptionStore defaultOptionStore = new OptionStore() { + + private final Map cache = new ConcurrentHashMap<>(); + + @Override + public String get(String key) { + return cache.get(key); + } + + @Override + public void put(String key, String value) { + if (StrUtil.isBlank(value)) { + remove(key); + } else { + cache.put(key, value); + } + } + + @Override + public void remove(String key) { + cache.remove(key); + } + }; + + } + + +} diff --git a/jpress-commons/src/main/java/io/jpress/base/BaseOptionsModel.java b/jpress-commons/src/main/java/io/jpress/base/BaseOptionsModel.java index 5d0ca6f1e2690964a978b2662f235ea5082c89fd..a9c42e000029c010dda32712a77edb560a55ad6b 100644 --- a/jpress-commons/src/main/java/io/jpress/base/BaseOptionsModel.java +++ b/jpress-commons/src/main/java/io/jpress/base/BaseOptionsModel.java @@ -1,104 +1,104 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.base; - - -import com.alibaba.fastjson.JSON; -import io.jboot.db.model.JbootModel; -import io.jboot.utils.StrUtil; - -import java.util.HashMap; -import java.util.Map; - -/** - * 用于扩展设置有Json字段的Model - * - * @param - */ -public class BaseOptionsModel> extends JbootModel { - - private static final String DEFAULT_OPTIONS_FIELDNAME = "options"; - - private Map optionMap; - - public void putOption(String key, String value) { - if (optionMap == null) { - optionMap = getOptionMap(); - } - optionMap.put(key, value); - } - - public String getOption(String key) { - if (optionMap == null) { - optionMap = getOptionMap(); - } - return optionMap.get(key); - } - - public Boolean getBoolOption(String key) { - String option = getOption(key); - return StrUtil.isBlank(option) ? null : Boolean.valueOf(option); - } - - public boolean getBoolOption(String key, boolean defaultValue) { - String option = getOption(key); - return StrUtil.isBlank(option) ? defaultValue : Boolean.valueOf(option); - } - - public Integer getIntOption(String key) { - String option = getOption(key); - return StrUtil.isBlank(option) ? null : Integer.valueOf(option); - } - - public int getIntOption(String key, int defaultValue) { - String option = getOption(key); - return StrUtil.isBlank(option) ? defaultValue : Integer.valueOf(option); - } - - public Map getOptionMap() { - String optionJson = getOptions(); - return StrUtil.isBlank(optionJson) ? new HashMap<>() : JSON.parseObject(optionJson, HashMap.class); - } - - - public void setOptions(java.lang.String options) { - set(getOptionsFieldName(), options); - } - - public java.lang.String getOptions() { - return getStr(getOptionsFieldName()); - } - - protected String getOptionsFieldName() { - return DEFAULT_OPTIONS_FIELDNAME; - } - - @Override - public boolean save() { - if (optionMap != null) { - setOptions(JSON.toJSONString(optionMap)); - } - return super.save(); - } - - @Override - public boolean update() { - if (optionMap != null) { - setOptions(JSON.toJSONString(optionMap)); - } - return super.update(); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.base; + + +import com.alibaba.fastjson.JSON; +import io.jboot.db.model.JbootModel; +import io.jboot.utils.StrUtil; + +import java.util.HashMap; +import java.util.Map; + +/** + * 用于扩展设置有Json字段的Model + * + * @param + */ +public class BaseOptionsModel> extends JbootModel { + + private static final String DEFAULT_OPTIONS_FIELDNAME = "options"; + + private Map optionMap; + + public void putOption(String key, String value) { + if (optionMap == null) { + optionMap = getOptionMap(); + } + optionMap.put(key, value); + } + + public String getOption(String key) { + if (optionMap == null) { + optionMap = getOptionMap(); + } + return optionMap.get(key); + } + + public Boolean getBoolOption(String key) { + String option = getOption(key); + return StrUtil.isBlank(option) ? null : Boolean.valueOf(option); + } + + public boolean getBoolOption(String key, boolean defaultValue) { + String option = getOption(key); + return StrUtil.isBlank(option) ? defaultValue : Boolean.valueOf(option); + } + + public Integer getIntOption(String key) { + String option = getOption(key); + return StrUtil.isBlank(option) ? null : Integer.valueOf(option); + } + + public int getIntOption(String key, int defaultValue) { + String option = getOption(key); + return StrUtil.isBlank(option) ? defaultValue : Integer.valueOf(option); + } + + public Map getOptionMap() { + String optionJson = getOptions(); + return StrUtil.isBlank(optionJson) ? new HashMap<>() : JSON.parseObject(optionJson, HashMap.class); + } + + + public void setOptions(java.lang.String options) { + set(getOptionsFieldName(), options); + } + + public java.lang.String getOptions() { + return getStr(getOptionsFieldName()); + } + + protected String getOptionsFieldName() { + return DEFAULT_OPTIONS_FIELDNAME; + } + + @Override + public boolean save() { + if (optionMap != null) { + setOptions(JSON.toJSONString(optionMap)); + } + return super.save(); + } + + @Override + public boolean update() { + if (optionMap != null) { + setOptions(JSON.toJSONString(optionMap)); + } + return super.update(); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/CacheObject.java b/jpress-commons/src/main/java/io/jpress/commons/CacheObject.java index d5a8c8bb56c0737fcef3956d5c87a3cfb73bdfe8..1138b296dbeadb6713ee6e96c5fec11571859548 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/CacheObject.java +++ b/jpress-commons/src/main/java/io/jpress/commons/CacheObject.java @@ -1,41 +1,41 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons; - -import io.jboot.Jboot; - -/** - * @author michael yang (fuhai999@gmail.com) - * @Date: 2020/2/29 - */ -public class CacheObject { - - private String name; - private String key; - - public CacheObject(String name, String key) { - this.name = name; - this.key = key; - } - - public void set(Object value) { - Jboot.getCache().put(name, key, value); - } - - public T get() { - return Jboot.getCache().get(name, key); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons; + +import io.jboot.Jboot; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/2/29 + */ +public class CacheObject { + + private String name; + private String key; + + public CacheObject(String name, String key) { + this.name = name; + this.key = key; + } + + public void set(Object value) { + Jboot.getCache().put(name, key, value); + } + + public T get() { + return Jboot.getCache().get(name, key); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/Copyer.java b/jpress-commons/src/main/java/io/jpress/commons/Copyer.java index f169efa6fa4b20e3d4233f26824f98b009fcfa49..1c966933f69a44badb46adc86ec9b27c52a66013 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/Copyer.java +++ b/jpress-commons/src/main/java/io/jpress/commons/Copyer.java @@ -1,39 +1,39 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons; - - -import io.jboot.db.model.JbootModel; - -import java.util.ArrayList; -import java.util.List; - -/** - * 由于 ehcache 缓存有这么一个特征:从缓存读取出来的缓存数据不能被再次修改,否则会出错 - * 因此,在某些场景下,我们读取的数据需要再次被修改,需要从缓存读取数据后 copy一份新的返回 - */ -public class Copyer { - - public static List copy(List list) { - if (list == null || list.isEmpty()) { - return null; - } - - List rlist = new ArrayList<>(list.size()); - list.forEach(m -> rlist.add((M) m.copy())); - return rlist; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons; + + +import io.jboot.db.model.JbootModel; + +import java.util.ArrayList; +import java.util.List; + +/** + * 由于 ehcache 缓存有这么一个特征:从缓存读取出来的缓存数据不能被再次修改,否则会出错 + * 因此,在某些场景下,我们读取的数据需要再次被修改,需要从缓存读取数据后 copy一份新的返回 + */ +public class Copyer { + + public static List copy(List list) { + if (list == null || list.isEmpty()) { + return null; + } + + List rlist = new ArrayList<>(list.size()); + list.forEach(m -> rlist.add((M) m.copy())); + return rlist; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/Msg.java b/jpress-commons/src/main/java/io/jpress/commons/Msg.java index 59f0bc846c3589c50a2d3eb165cb84fab3bebd2f..8e3564c2fe07dc751605404ac31eac094903ae21 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/Msg.java +++ b/jpress-commons/src/main/java/io/jpress/commons/Msg.java @@ -1,125 +1,125 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons; - -import java.io.Serializable; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 一个类似 JFinal 的 Ret 的类 - * @Package io.jpress.commons - */ -public class Msg implements Serializable { - - private static final String STATE_OK = "ok"; - private static final String STATE_FAIL = "fail"; - - private int errorCode = -1; //未知状态 - private String state; - private String message; - private Object data; - - public Msg() { - } - - public static Msg create() { - return new Msg(); - } - - public static Msg ok() { - return new Msg().setOk(); - } - - public static Msg ok(String message) { - return new Msg().setOk().setMessage(message); - } - - public static Msg fail() { - return new Msg().setFail(); - } - - public static Msg fail(int errorCode) { - return new Msg().setFail().setErrorCode(errorCode); - } - - public static Msg fail(String message) { - return new Msg().setFail().setMessage(message); - } - - public static Msg fail(int errorCode, String message) { - return new Msg() - .setFail() - .setErrorCode(errorCode) - .setMessage(message); - } - - public int getErrorCode() { - return errorCode; - } - - public Msg setErrorCode(int errorCode) { - this.errorCode = errorCode; - return this; - } - - public Msg setOk() { - this.setState(STATE_OK); - this.setErrorCode(0); - return this; - } - - public Msg setFail() { - this.setState(STATE_FAIL); - return this; - } - - public String getState() { - return state; - } - - public Msg setState(String state) { - this.state = state; - return this; - } - - public String getMessage() { - return message; - } - - public Msg setMessage(String message) { - this.message = message; - return this; - } - - public Object getData() { - return data; - } - - public Msg setData(Object data) { - this.data = data; - return this; - } - - public boolean isOk() { - return STATE_OK.equals(state); - } - - public boolean isFail() { - return STATE_FAIL.endsWith(state); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons; + +import java.io.Serializable; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 一个类似 JFinal 的 Ret 的类 + * @Package io.jpress.commons + */ +public class Msg implements Serializable { + + private static final String STATE_OK = "ok"; + private static final String STATE_FAIL = "fail"; + + private int errorCode = -1; //未知状态 + private String state; + private String message; + private Object data; + + public Msg() { + } + + public static Msg create() { + return new Msg(); + } + + public static Msg ok() { + return new Msg().setOk(); + } + + public static Msg ok(String message) { + return new Msg().setOk().setMessage(message); + } + + public static Msg fail() { + return new Msg().setFail(); + } + + public static Msg fail(int errorCode) { + return new Msg().setFail().setErrorCode(errorCode); + } + + public static Msg fail(String message) { + return new Msg().setFail().setMessage(message); + } + + public static Msg fail(int errorCode, String message) { + return new Msg() + .setFail() + .setErrorCode(errorCode) + .setMessage(message); + } + + public int getErrorCode() { + return errorCode; + } + + public Msg setErrorCode(int errorCode) { + this.errorCode = errorCode; + return this; + } + + public Msg setOk() { + this.setState(STATE_OK); + this.setErrorCode(0); + return this; + } + + public Msg setFail() { + this.setState(STATE_FAIL); + return this; + } + + public String getState() { + return state; + } + + public Msg setState(String state) { + this.state = state; + return this; + } + + public String getMessage() { + return message; + } + + public Msg setMessage(String message) { + this.message = message; + return this; + } + + public Object getData() { + return data; + } + + public Msg setData(Object data) { + this.data = data; + return this; + } + + public boolean isOk() { + return STATE_OK.equals(state); + } + + public boolean isFail() { + return STATE_FAIL.endsWith(state); + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/SnowFlake.java b/jpress-commons/src/main/java/io/jpress/commons/SnowFlake.java index 219a9c7d68cff0d3392b5733052a4da0172d316c..91f952211b0fc6932c5793d945519087d44edc6e 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/SnowFlake.java +++ b/jpress-commons/src/main/java/io/jpress/commons/SnowFlake.java @@ -1,99 +1,99 @@ -package io.jpress.commons; - - -public class SnowFlake { - - /** - * 起始的时间戳 - */ - private final static long START_STMP = 1480166465631L; - - /** - * 每一部分占用的位数 - */ - private final static long SEQUENCE_BIT = 12; //序列号占用的位数 - private final static long MACHINE_BIT = 5; //机器标识占用的位数 - private final static long DATACENTER_BIT = 5;//数据中心占用的位数 - - /** - * 每一部分的最大值 - */ - private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT); - private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT); - private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT); - - /** - * 每一部分向左的位移 - */ - private final static long MACHINE_LEFT = SEQUENCE_BIT; - private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; - private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; - - private long datacenterId; //数据中心 - private long machineId; //机器标识 - private long sequence = 0L; //序列号 - private long lastStmp = -1L;//上一次时间戳 - - public SnowFlake(long datacenterId, long machineId) { - if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { - throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0"); - } - if (machineId > MAX_MACHINE_NUM || machineId < 0) { - throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0"); - } - this.datacenterId = datacenterId; - this.machineId = machineId; - } - - /** - * 产生下一个ID - * @return - */ - public synchronized long genNextId() { - long currStmp = getNewstmp(); - if (currStmp < lastStmp) { - throw new RuntimeException("Clock moved backwards. Refusing to generate id"); - } - - if (currStmp == lastStmp) { - //相同毫秒内,序列号自增 - sequence = (sequence + 1) & MAX_SEQUENCE; - //同一毫秒的序列数已经达到最大 - if (sequence == 0L) { - currStmp = getNextMill(); - } - } else { - //不同毫秒内,序列号置为0 - sequence = 0L; - } - - lastStmp = currStmp; - - return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分 - | datacenterId << DATACENTER_LEFT //数据中心部分 - | machineId << MACHINE_LEFT //机器标识部分 - | sequence; //序列号部分 - } - - - private long getNextMill() { - long mill = getNewstmp(); - while (mill <= lastStmp) { - mill = getNewstmp(); - } - return mill; - } - - - private long getNewstmp() { - return System.currentTimeMillis(); - } - - public static void main(String[] args) { - SnowFlake snowFlake = new SnowFlake(1, 1); - for (int i = 0; i < 10; i++) { - System.out.println(snowFlake.genNextId()); - } - - } -} +package io.jpress.commons; + + +public class SnowFlake { + + /** + * 起始的时间戳 + */ + private final static long START_STMP = 1480166465631L; + + /** + * 每一部分占用的位数 + */ + private final static long SEQUENCE_BIT = 12; //序列号占用的位数 + private final static long MACHINE_BIT = 5; //机器标识占用的位数 + private final static long DATACENTER_BIT = 5;//数据中心占用的位数 + + /** + * 每一部分的最大值 + */ + private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT); + private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT); + private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT); + + /** + * 每一部分向左的位移 + */ + private final static long MACHINE_LEFT = SEQUENCE_BIT; + private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; + private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; + + private long datacenterId; //数据中心 + private long machineId; //机器标识 + private long sequence = 0L; //序列号 + private long lastStmp = -1L;//上一次时间戳 + + public SnowFlake(long datacenterId, long machineId) { + if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { + throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0"); + } + if (machineId > MAX_MACHINE_NUM || machineId < 0) { + throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0"); + } + this.datacenterId = datacenterId; + this.machineId = machineId; + } + + /** + * 产生下一个ID + * @return + */ + public synchronized long genNextId() { + long currStmp = getNewstmp(); + if (currStmp < lastStmp) { + throw new RuntimeException("Clock moved backwards. Refusing to generate id"); + } + + if (currStmp == lastStmp) { + //相同毫秒内,序列号自增 + sequence = (sequence + 1) & MAX_SEQUENCE; + //同一毫秒的序列数已经达到最大 + if (sequence == 0L) { + currStmp = getNextMill(); + } + } else { + //不同毫秒内,序列号置为0 + sequence = 0L; + } + + lastStmp = currStmp; + + return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分 + | datacenterId << DATACENTER_LEFT //数据中心部分 + | machineId << MACHINE_LEFT //机器标识部分 + | sequence; //序列号部分 + } + + + private long getNextMill() { + long mill = getNewstmp(); + while (mill <= lastStmp) { + mill = getNewstmp(); + } + return mill; + } + + + private long getNewstmp() { + return System.currentTimeMillis(); + } + + public static void main(String[] args) { + SnowFlake snowFlake = new SnowFlake(1, 1); + for (int i = 0; i < 10; i++) { + System.out.println(snowFlake.genNextId()); + } + + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/authcode/AuthCode.java b/jpress-commons/src/main/java/io/jpress/commons/authcode/AuthCode.java index f5966ad2db7b542a4cc111bdca55f970dae6e2a5..77973f9d6429336363082ac0c30ee6610c2ddaf1 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/authcode/AuthCode.java +++ b/jpress-commons/src/main/java/io/jpress/commons/authcode/AuthCode.java @@ -1,75 +1,75 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.authcode; - - -import io.jboot.utils.StrUtil; -import io.jpress.commons.utils.CommonsUtils; - -import java.io.Serializable; - -public class AuthCode implements Serializable { - - private String id; - private String code; - private long userId; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public long getUserId() { - return userId; - } - - public void setUserId(long userId) { - this.userId = userId; - } - - public static AuthCode newCode(long userId) { - AuthCode authCode = new AuthCode(); - - authCode.setId(StrUtil.uuid()); - authCode.setCode(CommonsUtils.generateCode()); - authCode.setUserId(userId); - - return authCode; - } - - public static AuthCode newCode() { - AuthCode authCode = new AuthCode(); - authCode.setId(StrUtil.uuid()); - authCode.setCode(CommonsUtils.generateCode()); - return authCode; - } - - - public static void save(AuthCode authCode){ - - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.authcode; + + +import io.jboot.utils.StrUtil; +import io.jpress.commons.utils.CommonsUtils; + +import java.io.Serializable; + +public class AuthCode implements Serializable { + + private String id; + private String code; + private long userId; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public static AuthCode newCode(long userId) { + AuthCode authCode = new AuthCode(); + + authCode.setId(StrUtil.uuid()); + authCode.setCode(CommonsUtils.generateCode()); + authCode.setUserId(userId); + + return authCode; + } + + public static AuthCode newCode() { + AuthCode authCode = new AuthCode(); + authCode.setId(StrUtil.uuid()); + authCode.setCode(CommonsUtils.generateCode()); + return authCode; + } + + + public static void save(AuthCode authCode){ + + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/authcode/AuthCodeKit.java b/jpress-commons/src/main/java/io/jpress/commons/authcode/AuthCodeKit.java index b61d68524efabe4be996ee9064a58fc400e5d59c..f3325fa23269f30488776f16a703c3fc0acf745a 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/authcode/AuthCodeKit.java +++ b/jpress-commons/src/main/java/io/jpress/commons/authcode/AuthCodeKit.java @@ -1,37 +1,37 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.authcode; - - -import io.jboot.Jboot; - -import java.io.Serializable; - -public class AuthCodeKit implements Serializable { - - private static final String CACHE_NAME = "authCode"; - - public static void save(AuthCode authCode) { - //有效期24小时 - Jboot.getCache().put(CACHE_NAME, authCode.getId(), authCode, 60 * 60 * 24); - - } - - - public static AuthCode get(String id) { - return Jboot.getCache().get(CACHE_NAME, id); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.authcode; + + +import io.jboot.Jboot; + +import java.io.Serializable; + +public class AuthCodeKit implements Serializable { + + private static final String CACHE_NAME = "authCode"; + + public static void save(AuthCode authCode) { + //有效期24小时 + Jboot.getCache().put(CACHE_NAME, authCode.getId(), authCode, 60 * 60 * 24); + + } + + + public static AuthCode get(String id) { + return Jboot.getCache().get(CACHE_NAME, id); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/bean/RenderList.java b/jpress-commons/src/main/java/io/jpress/commons/bean/RenderList.java index 82048945481a3077fbb19627c7bfcd44e3c06b0b..709f428f141818e5af66532f3b1d99f3d59fb743 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/bean/RenderList.java +++ b/jpress-commons/src/main/java/io/jpress/commons/bean/RenderList.java @@ -1,35 +1,35 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.bean; - -import java.util.ArrayList; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 用于在模板进行渲染,防止出错 get(index) 出错 - * @Package io.jpress.commons.bean - */ -public class RenderList extends ArrayList { - - @Override - public E get(int index) { - if (index >= size()) { - return null; - } - return super.get(index); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.bean; + +import java.util.ArrayList; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 用于在模板进行渲染,防止出错 get(index) 出错 + * @Package io.jpress.commons.bean + */ +public class RenderList extends ArrayList { + + @Override + public E get(int index) { + if (index >= size()) { + return null; + } + return super.get(index); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/dfa/DFAUtil.java b/jpress-commons/src/main/java/io/jpress/commons/dfa/DFAUtil.java index 971c036654ef8bfa2983682355a0b105715075fd..ae50c838d465c2cc13db01fa21388860c0f9f0aa 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/dfa/DFAUtil.java +++ b/jpress-commons/src/main/java/io/jpress/commons/dfa/DFAUtil.java @@ -1,150 +1,150 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.dfa; - -import com.jfinal.kit.LogKit; -import com.jfinal.kit.PathKit; -import io.jboot.utils.StrUtil; -import io.jpress.JPressOptions; -import io.jpress.commons.dfa.algorithm.DFAConfig; -import io.jpress.commons.dfa.algorithm.DFAFilter; -import io.jpress.commons.dfa.algorithm.DFAMatch; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * @author michael yang (fuhai999@gmail.com) - * @Date: 2020/1/5 - *

    - * https://github.com/aijingsun6/sensitive-words-filter - */ -public class DFAUtil { - - private static DFAConfig config = new DFAConfig.Builder() - .setIgnoreCase(true) - .setSupportPinyin(true) - .setSupportStopWord(true) - .setSupportDbc(true) - .setSupportSimpleTraditional(true) - .setStopWord("、,.。¥$%*&!@#-|[]【】") - .build(); - - private static DFAFilter sysFilter = new DFAFilter(config); - - private static String dynamicFilterTexts; - private static DFAFilter dynamicFilter; - - /** - * 需要在 App 启动的时候调用 init 进行初始化,方可使用 - */ - public static void init() { - File sysSensitiveWordsFile = new File(PathKit.getWebRootPath(), "WEB-INF/other/sys_sensitive_words.txt"); - initBy(sysSensitiveWordsFile); - } - - public static void initBy(File sensitiveWordsFile) { - try { - List lines = FileUtils.readLines(sensitiveWordsFile, "utf-8"); - for (String line : lines) { - if (line.startsWith("--") || StrUtil.isBlank(line)) { - continue; - } - sysFilter.putWord(line.trim(), 1); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - - public static boolean isContainsSensitiveWords(String content) { - - String filterContent = JPressOptions.get("text_filter_content"); - - if (StrUtil.isNotBlank(filterContent)) { - if (!Objects.equals(dynamicFilterTexts, filterContent)) { - if (isContainsSensitiveWords(dynamicFilter, content)) { - return true; - } - } else { - dynamicFilterTexts = filterContent; - DFAConfig config = new DFAConfig.Builder() - .setIgnoreCase(true) - .setSupportPinyin(true) - .setSupportStopWord(true) - .setSupportDbc(true) - .setSupportSimpleTraditional(true) - .setStopWord("、,.。¥$%*&!@#-|[]【】") - .build(); - dynamicFilter = new DFAFilter(config); - Set filterTexts = StrUtil.splitToSet(dynamicFilterTexts, ","); - for (String keyword : filterTexts) { - if (StrUtil.isNotBlank(keyword)) { - dynamicFilter.putWord(keyword, 1); - } - } - if (isContainsSensitiveWords(dynamicFilter, content)) { - return true; - } - } - } - - return isContainsSensitiveWords(sysFilter, content); - } - - private static boolean isContainsSensitiveWords(DFAFilter filter, String content) { - if (filter == null || StrUtil.isBlank(content)) { - return false; - } - List matches = filter.matchWord(content); - printDFAMatches(matches); - return matches != null && matches.size() > 0; - } - - - private static void printDFAMatches(List matches) { - if (matches == null || matches.isEmpty()) { - return; - } - StringBuilder sb = new StringBuilder(); - int i = 0; - for (DFAMatch match : matches) { - if (match != null) { - sb.append(match.getWord()); - } - if (i < matches.size() - 1) { - sb.append(","); - } - i++; - } - LogKit.error("Matched Sensitive Words : " + sb.toString()); - } - - - public static void main(String[] args) { - String text = ""; - File file = new File(PathKit.getRootClassPath(),"../../../jpress-web/src/main/webapp/WEB-INF/other/sys_sensitive_words.txt"); - initBy(file); - System.out.println(isContainsSensitiveWords(text)); - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.dfa; + +import com.jfinal.kit.LogKit; +import com.jfinal.kit.PathKit; +import io.jboot.utils.StrUtil; +import io.jpress.JPressOptions; +import io.jpress.commons.dfa.algorithm.DFAConfig; +import io.jpress.commons.dfa.algorithm.DFAFilter; +import io.jpress.commons.dfa.algorithm.DFAMatch; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/1/5 + *

    + * https://github.com/aijingsun6/sensitive-words-filter + */ +public class DFAUtil { + + private static DFAConfig config = new DFAConfig.Builder() + .setIgnoreCase(true) + .setSupportPinyin(true) + .setSupportStopWord(true) + .setSupportDbc(true) + .setSupportSimpleTraditional(true) + .setStopWord("、,.。¥$%*&!@#-|[]【】") + .build(); + + private static DFAFilter sysFilter = new DFAFilter(config); + + private static String dynamicFilterTexts; + private static DFAFilter dynamicFilter; + + /** + * 需要在 App 启动的时候调用 init 进行初始化,方可使用 + */ + public static void init() { + File sysSensitiveWordsFile = new File(PathKit.getWebRootPath(), "WEB-INF/other/sys_sensitive_words.txt"); + initBy(sysSensitiveWordsFile); + } + + public static void initBy(File sensitiveWordsFile) { + try { + List lines = FileUtils.readLines(sensitiveWordsFile, "utf-8"); + for (String line : lines) { + if (line.startsWith("--") || StrUtil.isBlank(line)) { + continue; + } + sysFilter.putWord(line.trim(), 1); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + + public static boolean isContainsSensitiveWords(String content) { + + String filterContent = JPressOptions.get("text_filter_content"); + + if (StrUtil.isNotBlank(filterContent)) { + if (!Objects.equals(dynamicFilterTexts, filterContent)) { + if (isContainsSensitiveWords(dynamicFilter, content)) { + return true; + } + } else { + dynamicFilterTexts = filterContent; + DFAConfig config = new DFAConfig.Builder() + .setIgnoreCase(true) + .setSupportPinyin(true) + .setSupportStopWord(true) + .setSupportDbc(true) + .setSupportSimpleTraditional(true) + .setStopWord("、,.。¥$%*&!@#-|[]【】") + .build(); + dynamicFilter = new DFAFilter(config); + Set filterTexts = StrUtil.splitToSet(dynamicFilterTexts, ","); + for (String keyword : filterTexts) { + if (StrUtil.isNotBlank(keyword)) { + dynamicFilter.putWord(keyword, 1); + } + } + if (isContainsSensitiveWords(dynamicFilter, content)) { + return true; + } + } + } + + return isContainsSensitiveWords(sysFilter, content); + } + + private static boolean isContainsSensitiveWords(DFAFilter filter, String content) { + if (filter == null || StrUtil.isBlank(content)) { + return false; + } + List matches = filter.matchWord(content); + printDFAMatches(matches); + return matches != null && matches.size() > 0; + } + + + private static void printDFAMatches(List matches) { + if (matches == null || matches.isEmpty()) { + return; + } + StringBuilder sb = new StringBuilder(); + int i = 0; + for (DFAMatch match : matches) { + if (match != null) { + sb.append(match.getWord()); + } + if (i < matches.size() - 1) { + sb.append(","); + } + i++; + } + LogKit.error("Matched Sensitive Words : " + sb.toString()); + } + + + public static void main(String[] args) { + String text = ""; + File file = new File(PathKit.getRootClassPath(),"../../../jpress-web/src/main/webapp/WEB-INF/other/sys_sensitive_words.txt"); + initBy(file); + System.out.println(isContainsSensitiveWords(text)); + } + + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/BCConvert.java b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/BCConvert.java index b11758f13baea3e286a63114dd36d4bae7515cb0..916e2ddb0bd26c43ed5af6c4e69ddcedfcbf5a3a 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/BCConvert.java +++ b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/BCConvert.java @@ -1,63 +1,63 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.dfa.algorithm; - - -public class BCConvert { - - public static final char SBC_SPACE = 12288; // 全角空格 12288 - - public static final char DBC_SPACE = 32; //半角空格 32 - - // ASCII character 33-126 <-> unicode 65281-65374 - public static final char ASCII_START = 33; - - public static final char ASCII_END = 126; - - public static final char UNICODE_START = 65281; - - public static final char UNICODE_END = 65374; - - public static final char DBC_SBC_STEP = 65248; // 全角半角转换间隔 - - /** - * 全角转半角 - */ - public static char sbc2dbc(char src){ - if (src == SBC_SPACE) { - return DBC_SPACE; - } - - if (src >= UNICODE_START && src <= UNICODE_END) { - return (char) (src - DBC_SBC_STEP); - } - - return src; - } - /** - * 半角转全角 - */ - public static char dbc2sbc(char src){ - if (src == DBC_SPACE) { - return SBC_SPACE; - } - if (src <= ASCII_END) { - return (char) (src + DBC_SBC_STEP); - } - return src; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.dfa.algorithm; + + +public class BCConvert { + + public static final char SBC_SPACE = 12288; // 全角空格 12288 + + public static final char DBC_SPACE = 32; //半角空格 32 + + // ASCII character 33-126 <-> unicode 65281-65374 + public static final char ASCII_START = 33; + + public static final char ASCII_END = 126; + + public static final char UNICODE_START = 65281; + + public static final char UNICODE_END = 65374; + + public static final char DBC_SBC_STEP = 65248; // 全角半角转换间隔 + + /** + * 全角转半角 + */ + public static char sbc2dbc(char src){ + if (src == SBC_SPACE) { + return DBC_SPACE; + } + + if (src >= UNICODE_START && src <= UNICODE_END) { + return (char) (src - DBC_SBC_STEP); + } + + return src; + } + /** + * 半角转全角 + */ + public static char dbc2sbc(char src){ + if (src == DBC_SPACE) { + return SBC_SPACE; + } + if (src <= ASCII_END) { + return (char) (src + DBC_SBC_STEP); + } + return src; + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAConfig.java b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAConfig.java index 3e6fbd7d3127f4e2130686297b25597f784bb933..011b33126b2fb77e72c3a5f031e1cb804cc711f2 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAConfig.java +++ b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAConfig.java @@ -1,188 +1,188 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.dfa.algorithm; - -import java.util.HashSet; -import java.util.Set; - - -public class DFAConfig { - - /** - * 是否支持拼音,配置汉字只能识别汉字,不能识别拼音 - */ - private boolean supportPinyin = false; - /** - * 忽略大小写,默认大小写敏感 - */ - private boolean ignoreCase = false; - /** - * 支持简体,繁体,默认不支持,配置简体只能识别简体 - */ - private boolean supportSimpleTraditional = false; - /** - * 支持半角全角,默认不支持,配置半角只能识别半角 - */ - private boolean supportDbc = false; - /** - * 支持停顿词,默认不支持,字之间使用别的字符隔开不识别 - */ - private boolean supportStopWord = false; - - private String stopWord = ""; - - private Set stopWordCharSet = new HashSet<>(); - - public boolean isSupportPinyin() { - return supportPinyin; - } - - public void setSupportPinyin(boolean supportPinyin) { - this.supportPinyin = supportPinyin; - } - - public boolean isIgnoreCase() { - return ignoreCase; - } - - public void setIgnoreCase(boolean ignoreCase) { - this.ignoreCase = ignoreCase; - } - - public boolean isSupportSimpleTraditional() { - return supportSimpleTraditional; - } - - public void setSupportSimpleTraditional(boolean supportSimpleTraditional) { - this.supportSimpleTraditional = supportSimpleTraditional; - } - - public boolean isSupportDbc() { - return supportDbc; - } - - public void setSupportDbc(boolean supportDbc) { - this.supportDbc = supportDbc; - } - - public boolean isSupportStopWord() { - return supportStopWord; - } - - public void setSupportStopWord(boolean supportStopWord) { - this.supportStopWord = supportStopWord; - } - - public String getStopWord() { - return stopWord; - } - - public void setStopWord(String stopWord) { - this.stopWord = stopWord; - this.stopWordCharSet.clear(); - if (this.stopWord != null) { - for (char c : this.stopWord.toCharArray()) { - stopWordCharSet.add(c); - } - } - } - - public boolean containsStopChar(char ch) { - return this.stopWordCharSet.contains(ch); - } - - public DFAConfig() { - - } - - public static class Builder { - - private boolean supportPinyin = false; - - private boolean ignoreCase = false; - - private boolean supportSimpleTraditional = false; - - private boolean supportDbc = false; - - private boolean supportStopWord = false; - - private String stopWord = ""; - - public Builder() { - - } - - /** - * 是否支持拼音,配置汉字只能识别汉字,不能识别拼音 - */ - public Builder setSupportPinyin(boolean support) { - this.supportPinyin = support; - return this; - } - - /** - * 忽略大小写,默认大小写敏感 - */ - public Builder setIgnoreCase(boolean ignoreCase) { - this.ignoreCase = ignoreCase; - return this; - } - - /** - * 支持简体,繁体,默认不支持,配置简体只能识别简体 - */ - public Builder setSupportSimpleTraditional(boolean supportSimpleTraditional) { - this.supportSimpleTraditional = supportSimpleTraditional; - return this; - } - - /** - * 支持半角全角,默认不支持,配置半角只能识别半角 - */ - public Builder setSupportDbc(boolean supportDbc) { - this.supportDbc = supportDbc; - return this; - } - - /** - * 支持停顿词,默认不支持,字之间使用别的字符隔开不识别 - */ - public Builder setSupportStopWord(boolean supportStopWord) { - this.supportStopWord = supportStopWord; - return this; - } - - /** - * 设置停顿词 - */ - public Builder setStopWord(String stopWord) { - this.stopWord = stopWord; - return this; - } - - public DFAConfig build() { - DFAConfig config = new DFAConfig(); - config.setIgnoreCase(this.ignoreCase); - config.setSupportStopWord(this.supportStopWord); - config.setStopWord(this.stopWord); - config.setSupportDbc(this.supportDbc); - config.setSupportPinyin(this.supportPinyin); - config.setSupportSimpleTraditional(this.supportSimpleTraditional); - return config; - } - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.dfa.algorithm; + +import java.util.HashSet; +import java.util.Set; + + +public class DFAConfig { + + /** + * 是否支持拼音,配置汉字只能识别汉字,不能识别拼音 + */ + private boolean supportPinyin = false; + /** + * 忽略大小写,默认大小写敏感 + */ + private boolean ignoreCase = false; + /** + * 支持简体,繁体,默认不支持,配置简体只能识别简体 + */ + private boolean supportSimpleTraditional = false; + /** + * 支持半角全角,默认不支持,配置半角只能识别半角 + */ + private boolean supportDbc = false; + /** + * 支持停顿词,默认不支持,字之间使用别的字符隔开不识别 + */ + private boolean supportStopWord = false; + + private String stopWord = ""; + + private Set stopWordCharSet = new HashSet<>(); + + public boolean isSupportPinyin() { + return supportPinyin; + } + + public void setSupportPinyin(boolean supportPinyin) { + this.supportPinyin = supportPinyin; + } + + public boolean isIgnoreCase() { + return ignoreCase; + } + + public void setIgnoreCase(boolean ignoreCase) { + this.ignoreCase = ignoreCase; + } + + public boolean isSupportSimpleTraditional() { + return supportSimpleTraditional; + } + + public void setSupportSimpleTraditional(boolean supportSimpleTraditional) { + this.supportSimpleTraditional = supportSimpleTraditional; + } + + public boolean isSupportDbc() { + return supportDbc; + } + + public void setSupportDbc(boolean supportDbc) { + this.supportDbc = supportDbc; + } + + public boolean isSupportStopWord() { + return supportStopWord; + } + + public void setSupportStopWord(boolean supportStopWord) { + this.supportStopWord = supportStopWord; + } + + public String getStopWord() { + return stopWord; + } + + public void setStopWord(String stopWord) { + this.stopWord = stopWord; + this.stopWordCharSet.clear(); + if (this.stopWord != null) { + for (char c : this.stopWord.toCharArray()) { + stopWordCharSet.add(c); + } + } + } + + public boolean containsStopChar(char ch) { + return this.stopWordCharSet.contains(ch); + } + + public DFAConfig() { + + } + + public static class Builder { + + private boolean supportPinyin = false; + + private boolean ignoreCase = false; + + private boolean supportSimpleTraditional = false; + + private boolean supportDbc = false; + + private boolean supportStopWord = false; + + private String stopWord = ""; + + public Builder() { + + } + + /** + * 是否支持拼音,配置汉字只能识别汉字,不能识别拼音 + */ + public Builder setSupportPinyin(boolean support) { + this.supportPinyin = support; + return this; + } + + /** + * 忽略大小写,默认大小写敏感 + */ + public Builder setIgnoreCase(boolean ignoreCase) { + this.ignoreCase = ignoreCase; + return this; + } + + /** + * 支持简体,繁体,默认不支持,配置简体只能识别简体 + */ + public Builder setSupportSimpleTraditional(boolean supportSimpleTraditional) { + this.supportSimpleTraditional = supportSimpleTraditional; + return this; + } + + /** + * 支持半角全角,默认不支持,配置半角只能识别半角 + */ + public Builder setSupportDbc(boolean supportDbc) { + this.supportDbc = supportDbc; + return this; + } + + /** + * 支持停顿词,默认不支持,字之间使用别的字符隔开不识别 + */ + public Builder setSupportStopWord(boolean supportStopWord) { + this.supportStopWord = supportStopWord; + return this; + } + + /** + * 设置停顿词 + */ + public Builder setStopWord(String stopWord) { + this.stopWord = stopWord; + return this; + } + + public DFAConfig build() { + DFAConfig config = new DFAConfig(); + config.setIgnoreCase(this.ignoreCase); + config.setSupportStopWord(this.supportStopWord); + config.setStopWord(this.stopWord); + config.setSupportDbc(this.supportDbc); + config.setSupportPinyin(this.supportPinyin); + config.setSupportSimpleTraditional(this.supportSimpleTraditional); + return config; + } + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAFilter.java b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAFilter.java index bfa38e7f88e704584de5d5aadbcdfad1069f375b..df5ad568049da4046ae20fc0e2cb30ce2592d064 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAFilter.java +++ b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAFilter.java @@ -1,265 +1,265 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.dfa.algorithm; - -import com.github.houbb.opencc4j.util.ZhConverterUtil; -import com.github.promeg.pinyinhelper.Pinyin; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - - -public class DFAFilter { - - /** - * 最大的拼音 chuang - */ - private static final int PINYIN_SIZE_MAX = 6; - - private final DFANode root = new DFANode('R', false); - - public DFANode getRoot() { - return this.root; - } - - private DFAConfig config = new DFAConfig(); - - public DFAConfig getConfig() { - return config; - } - - public void setConfig(DFAConfig config) { - this.config = config; - } - - public DFAFilter() { - - } - - public DFAFilter(DFAConfig config) { - this.config = config; - } - - private static boolean isEmpty(String s) { - return s == null || s.length() < 1; - } - - - public void putWord(final String word, final Comparable ext) { - if (isEmpty(word)) { - return; - } - putWord(this.root, word, 0, ext); - } - - private void putWord(final DFANode prev, final String word, final int idx, final Comparable ext) { - final boolean last = idx == word.length() - 1; - final char ch = word.charAt(idx); - if (this.config.isSupportStopWord() && this.config.containsStopChar(ch)) { - // c 是停顿词 - if (last && prev != this.root) { - prev.leaf = true; - if (prev.ext == null) { - prev.ext = ext; - } else if (ext != null && ext.compareTo(prev.ext) > 0) { - prev.ext = ext; - } - return; - } - putWord(prev, word, idx + 1, ext); - return; - } - // c 不是停顿词 - - //先进行字符操作 - this.putCh(prev, word, idx, ch, last, ext); - if (this.config.isSupportPinyin() && Pinyin.isChinese(ch)) { - String pinyin = Pinyin.toPinyin(ch); - this.putPinyin(prev, word, idx, pinyin, last, ext); - } - } - - private void putCh(final DFANode prev, final String word, final int idx, char ch, boolean last, final Comparable ext) { - DFANode find = prev.getNode(ch); - if (find == null) { - find = new DFANode(ch, last); - prev.putNode(ch, find); - } - - if (last) { - find.leaf = true; - find.word = word; - - if (find.ext == null) { - find.ext = ext; - } else if (ext != null && ext.compareTo(find.ext) > 0) { - find.ext = ext; - } - - return; - } - this.putWord(find, word, idx + 1, ext); - } - - private void putPinyin(final DFANode prev, final String word, final int idx, String pinyin, boolean last, final Comparable ext) { - DFANode find = prev.getNode(pinyin); - if (find == null) { - char ch = word.charAt(idx); - find = prev.getNode(ch); - if (find == null) { - find = new DFANode(ch, last); - } - prev.putNode(pinyin, find); - } - if (last) { - find.leaf = true; - find.word = word; - if (find.ext == null) { - find.ext = ext; - } else if (ext != null && ext.compareTo(find.ext) > 0) { - find.ext = ext; - } - return; - } - this.putWord(find, word, idx + 1, ext); - } - - public List matchWord(final String word) { - if (isEmpty(word)) { - return Collections.emptyList(); - } - List acc = new LinkedList<>(); - for (int i = 0; i < word.length(); i++) { - matchWord2(this.root, word, i, i, acc); - } - return acc; - } - - private void matchWord2(final DFANode prev, final String word, final int originStart, final int start, final List acc) { - if (start > word.length() - 1) { - return; - } - char ch = word.charAt(start); - - if (this.config.isSupportStopWord() && this.config.containsStopChar(ch)) { - //停顿词 - if (start == originStart) { - return; - } - matchWord2(prev, word, originStart, start + 1, acc); - return; - } - - // 字符寻找 - DFANode cNode = prev.getNode(ch); - if (cNode != null) { - if (cNode.leaf) { - // 叶子节点 - acc.add(new DFAMatch(originStart, start, cNode)); - } - matchWord2(cNode, word, originStart, start + 1, acc); - } - - if (this.config.isIgnoreCase()) { - // 忽略大小写 - char low = Character.toLowerCase(ch); - char upper = Character.toUpperCase(ch); - this.matchWordChar(ch, low, prev, word, originStart, start, acc); - this.matchWordChar(ch, upper, prev, word, originStart, start, acc); - } - - if (this.config.isSupportDbc()) { - // 支持全角半角 - char dbc = BCConvert.sbc2dbc(ch); - char sbc = BCConvert.dbc2sbc(ch); - this.matchWordChar(ch, dbc, prev, word, originStart, start, acc); - this.matchWordChar(ch, sbc, prev, word, originStart, start, acc); - } - - if (this.config.isSupportSimpleTraditional() && Pinyin.isChinese(ch)) { - // 支持简体,繁体 - String simple = ZhConverterUtil.convertToSimple(String.valueOf(ch)); - char simpleChar = simple.charAt(0); - String trad = ZhConverterUtil.convertToTraditional(String.valueOf(ch)); - char tradChar = trad.charAt(0); - this.matchWordChar(ch, simpleChar, prev, word, originStart, start, acc); - this.matchWordChar(ch, tradChar, prev, word, originStart, start, acc); - } - - if (this.config.isSupportPinyin() && Character.isLetter(ch)) { - // 支持拼音,但是要是 letter - StringBuilder sb = new StringBuilder(); - sb.append(Character.toUpperCase(ch)); - int size = 1; - int pinyinSize = 1; - - while (pinyinSize <= PINYIN_SIZE_MAX && start + size < word.length()) { - char c = word.charAt(start + size); - //停顿词 - if (config.isSupportStopWord() && config.containsStopChar(c)) { - size += 1; - continue; - } - if (!Character.isLetter(c)) { - break; - } - sb.append(Character.toUpperCase(c)); - this.matchWordPinyin(sb.toString(), prev, word, originStart, start + size, acc); - size += 1; - pinyinSize += 1; - } - } - } - - - private void matchWordChar(final char oriCh, final char ch, final DFANode prev, final String word, final int originStart, final int start, final List acc) { - if (oriCh == ch) { - return; - } - DFANode cNode = prev.getNode(ch); - if (cNode != null) { - if (cNode.leaf) { - acc.add(new DFAMatch(originStart, start, cNode)); - } - matchWord2(cNode, word, originStart, start + 1, acc); - } - } - - private void matchWordPinyin(final String pinyin, final DFANode prev, final String word, final int originStart, final int start, final List acc) { - DFANode sNode = prev.getNode(pinyin); - if (sNode != null) { - if (sNode.leaf) { - acc.add(new DFAMatch(originStart, start, sNode)); - } - matchWord2(sNode, word, originStart, start + 1, acc); - } - } - - public String replaceWord(final String origin, final List matches, final char c) { - if (isEmpty(origin)) { - return origin; - } - char[] chars = origin.toCharArray(); - int length = chars.length; - for (DFAMatch match : matches) { - for (int idx = match.getStart(); idx <= match.getEnd() && idx < length; idx++) { - chars[idx] = c; - } - } - return new String(chars); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.dfa.algorithm; + +import com.github.houbb.opencc4j.util.ZhConverterUtil; +import com.github.promeg.pinyinhelper.Pinyin; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + + +public class DFAFilter { + + /** + * 最大的拼音 chuang + */ + private static final int PINYIN_SIZE_MAX = 6; + + private final DFANode root = new DFANode('R', false); + + public DFANode getRoot() { + return this.root; + } + + private DFAConfig config = new DFAConfig(); + + public DFAConfig getConfig() { + return config; + } + + public void setConfig(DFAConfig config) { + this.config = config; + } + + public DFAFilter() { + + } + + public DFAFilter(DFAConfig config) { + this.config = config; + } + + private static boolean isEmpty(String s) { + return s == null || s.length() < 1; + } + + + public void putWord(final String word, final Comparable ext) { + if (isEmpty(word)) { + return; + } + putWord(this.root, word, 0, ext); + } + + private void putWord(final DFANode prev, final String word, final int idx, final Comparable ext) { + final boolean last = idx == word.length() - 1; + final char ch = word.charAt(idx); + if (this.config.isSupportStopWord() && this.config.containsStopChar(ch)) { + // c 是停顿词 + if (last && prev != this.root) { + prev.leaf = true; + if (prev.ext == null) { + prev.ext = ext; + } else if (ext != null && ext.compareTo(prev.ext) > 0) { + prev.ext = ext; + } + return; + } + putWord(prev, word, idx + 1, ext); + return; + } + // c 不是停顿词 + + //先进行字符操作 + this.putCh(prev, word, idx, ch, last, ext); + if (this.config.isSupportPinyin() && Pinyin.isChinese(ch)) { + String pinyin = Pinyin.toPinyin(ch); + this.putPinyin(prev, word, idx, pinyin, last, ext); + } + } + + private void putCh(final DFANode prev, final String word, final int idx, char ch, boolean last, final Comparable ext) { + DFANode find = prev.getNode(ch); + if (find == null) { + find = new DFANode(ch, last); + prev.putNode(ch, find); + } + + if (last) { + find.leaf = true; + find.word = word; + + if (find.ext == null) { + find.ext = ext; + } else if (ext != null && ext.compareTo(find.ext) > 0) { + find.ext = ext; + } + + return; + } + this.putWord(find, word, idx + 1, ext); + } + + private void putPinyin(final DFANode prev, final String word, final int idx, String pinyin, boolean last, final Comparable ext) { + DFANode find = prev.getNode(pinyin); + if (find == null) { + char ch = word.charAt(idx); + find = prev.getNode(ch); + if (find == null) { + find = new DFANode(ch, last); + } + prev.putNode(pinyin, find); + } + if (last) { + find.leaf = true; + find.word = word; + if (find.ext == null) { + find.ext = ext; + } else if (ext != null && ext.compareTo(find.ext) > 0) { + find.ext = ext; + } + return; + } + this.putWord(find, word, idx + 1, ext); + } + + public List matchWord(final String word) { + if (isEmpty(word)) { + return Collections.emptyList(); + } + List acc = new LinkedList<>(); + for (int i = 0; i < word.length(); i++) { + matchWord2(this.root, word, i, i, acc); + } + return acc; + } + + private void matchWord2(final DFANode prev, final String word, final int originStart, final int start, final List acc) { + if (start > word.length() - 1) { + return; + } + char ch = word.charAt(start); + + if (this.config.isSupportStopWord() && this.config.containsStopChar(ch)) { + //停顿词 + if (start == originStart) { + return; + } + matchWord2(prev, word, originStart, start + 1, acc); + return; + } + + // 字符寻找 + DFANode cNode = prev.getNode(ch); + if (cNode != null) { + if (cNode.leaf) { + // 叶子节点 + acc.add(new DFAMatch(originStart, start, cNode)); + } + matchWord2(cNode, word, originStart, start + 1, acc); + } + + if (this.config.isIgnoreCase()) { + // 忽略大小写 + char low = Character.toLowerCase(ch); + char upper = Character.toUpperCase(ch); + this.matchWordChar(ch, low, prev, word, originStart, start, acc); + this.matchWordChar(ch, upper, prev, word, originStart, start, acc); + } + + if (this.config.isSupportDbc()) { + // 支持全角半角 + char dbc = BCConvert.sbc2dbc(ch); + char sbc = BCConvert.dbc2sbc(ch); + this.matchWordChar(ch, dbc, prev, word, originStart, start, acc); + this.matchWordChar(ch, sbc, prev, word, originStart, start, acc); + } + + if (this.config.isSupportSimpleTraditional() && Pinyin.isChinese(ch)) { + // 支持简体,繁体 + String simple = ZhConverterUtil.convertToSimple(String.valueOf(ch)); + char simpleChar = simple.charAt(0); + String trad = ZhConverterUtil.convertToTraditional(String.valueOf(ch)); + char tradChar = trad.charAt(0); + this.matchWordChar(ch, simpleChar, prev, word, originStart, start, acc); + this.matchWordChar(ch, tradChar, prev, word, originStart, start, acc); + } + + if (this.config.isSupportPinyin() && Character.isLetter(ch)) { + // 支持拼音,但是要是 letter + StringBuilder sb = new StringBuilder(); + sb.append(Character.toUpperCase(ch)); + int size = 1; + int pinyinSize = 1; + + while (pinyinSize <= PINYIN_SIZE_MAX && start + size < word.length()) { + char c = word.charAt(start + size); + //停顿词 + if (config.isSupportStopWord() && config.containsStopChar(c)) { + size += 1; + continue; + } + if (!Character.isLetter(c)) { + break; + } + sb.append(Character.toUpperCase(c)); + this.matchWordPinyin(sb.toString(), prev, word, originStart, start + size, acc); + size += 1; + pinyinSize += 1; + } + } + } + + + private void matchWordChar(final char oriCh, final char ch, final DFANode prev, final String word, final int originStart, final int start, final List acc) { + if (oriCh == ch) { + return; + } + DFANode cNode = prev.getNode(ch); + if (cNode != null) { + if (cNode.leaf) { + acc.add(new DFAMatch(originStart, start, cNode)); + } + matchWord2(cNode, word, originStart, start + 1, acc); + } + } + + private void matchWordPinyin(final String pinyin, final DFANode prev, final String word, final int originStart, final int start, final List acc) { + DFANode sNode = prev.getNode(pinyin); + if (sNode != null) { + if (sNode.leaf) { + acc.add(new DFAMatch(originStart, start, sNode)); + } + matchWord2(sNode, word, originStart, start + 1, acc); + } + } + + public String replaceWord(final String origin, final List matches, final char c) { + if (isEmpty(origin)) { + return origin; + } + char[] chars = origin.toCharArray(); + int length = chars.length; + for (DFAMatch match : matches) { + for (int idx = match.getStart(); idx <= match.getEnd() && idx < length; idx++) { + chars[idx] = c; + } + } + return new String(chars); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAMatch.java b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAMatch.java index 13cf4ed0dca315e1471ca26a621d6dc35da54e2d..2adcbec72be2eba026791a972ec21a1851e8113b 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAMatch.java +++ b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFAMatch.java @@ -1,47 +1,47 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.dfa.algorithm; - - -public class DFAMatch { - - private int start; - private int end; - - private DFANode matched; - - public int getStart() { - return start; - } - - public int getEnd() { - return end; - } - - public DFANode getMatched() { - return matched; - } - - public DFAMatch(int start, int end, DFANode matched) { - this.start = start; - this.end = end; - this.matched = matched; - } - - public String getWord() { - return this.matched.word; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.dfa.algorithm; + + +public class DFAMatch { + + private int start; + private int end; + + private DFANode matched; + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } + + public DFANode getMatched() { + return matched; + } + + public DFAMatch(int start, int end, DFANode matched) { + this.start = start; + this.end = end; + this.matched = matched; + } + + public String getWord() { + return this.matched.word; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFANode.java b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFANode.java index 39f07a075dcbe30c23a2994962a58394c6b0c730..cf079dfb274f86505632e15253c02f5f054a29a4 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFANode.java +++ b/jpress-commons/src/main/java/io/jpress/commons/dfa/algorithm/DFANode.java @@ -1,75 +1,75 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.dfa.algorithm; - -import java.util.HashMap; -import java.util.Map; - - -public class DFANode { - - protected final char ch; - - protected boolean leaf; - - protected String word = null; - - protected Comparable ext; - - protected DFANode parent; - - /** - * chat -> node - */ - private Map cMap = new HashMap<>(0); - - /** - * string -> node - * 用于拼音 - */ - private Map sMap = new HashMap<>(0); - - public Map getcMap() { - return cMap; - } - - public Map getsMap() { - return sMap; - } - - public DFANode getNode(char c) { - return this.cMap.get(c); - } - - public DFANode getNode(String s) { - return this.sMap.get(s); - } - - public void putNode(char c, DFANode node) { - this.cMap.put(c, node); - node.parent = this; - } - - public void putNode(String s, DFANode node) { - this.sMap.put(s, node); - node.parent = this; - } - - public DFANode(char ch, boolean leaf) { - this.ch = ch; - this.leaf = leaf; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.dfa.algorithm; + +import java.util.HashMap; +import java.util.Map; + + +public class DFANode { + + protected final char ch; + + protected boolean leaf; + + protected String word = null; + + protected Comparable ext; + + protected DFANode parent; + + /** + * chat -> node + */ + private Map cMap = new HashMap<>(0); + + /** + * string -> node + * 用于拼音 + */ + private Map sMap = new HashMap<>(0); + + public Map getcMap() { + return cMap; + } + + public Map getsMap() { + return sMap; + } + + public DFANode getNode(char c) { + return this.cMap.get(c); + } + + public DFANode getNode(String s) { + return this.sMap.get(s); + } + + public void putNode(char c, DFANode node) { + this.cMap.put(c, node); + node.parent = this; + } + + public void putNode(String s, DFANode node) { + this.sMap.put(s, node); + node.parent = this; + } + + public DFANode(char ch, boolean leaf) { + this.ch = ch; + this.leaf = leaf; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/directive/DirectveKit.java b/jpress-commons/src/main/java/io/jpress/commons/directive/DirectveKit.java index 7f8a09a502809afda90299f36f299c3c41878398..20e49b021777ca6c58a0155bd58d1bf5df73fcac 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/directive/DirectveKit.java +++ b/jpress-commons/src/main/java/io/jpress/commons/directive/DirectveKit.java @@ -1,56 +1,56 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.directive; - - -public class DirectveKit { - - - public static String replacePageNumber(String url, int pageNumber) { - - int dotIndexOf = url.lastIndexOf("."); - int splitIndexOf = url.lastIndexOf("-"); - - if (dotIndexOf < 0 & splitIndexOf < 0) { - return url + "-" + pageNumber; - } - - if (dotIndexOf < 0 && splitIndexOf > 0) { - return url.substring(0, splitIndexOf) + "-" + pageNumber; - } - - if (dotIndexOf > 0 && splitIndexOf < 0) { - return url.substring(0, dotIndexOf) + "-" + pageNumber + url.substring(dotIndexOf); - } - - //if (dotIndexOf > 0 && spitIndexOf >0){ - return url.substring(0, splitIndexOf) + "-" + pageNumber + url.substring(dotIndexOf); - } - - public static void main(String[] args) { - - System.out.println(replacePageNumber("/aa/bb/all-1", 123)); - System.out.println(replacePageNumber("/aa/bb/cc", 123)); - System.out.println(replacePageNumber("/aa/bb/cc.html", 123)); - System.out.println(replacePageNumber("/aa/bb/cc-33-44.html", 123)); - System.out.println(replacePageNumber("/aa/bb/cc-333.html", 123)); - System.out.println(replacePageNumber("/aa/bb/cc-1.html", 123)); - System.out.println(replacePageNumber("/aa/bb/cc-31", 123)); - System.out.println(replacePageNumber("/aa/bb/cc-", 123)); - - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.directive; + + +public class DirectveKit { + + + public static String replacePageNumber(String url, int pageNumber) { + + int dotIndexOf = url.lastIndexOf("."); + int splitIndexOf = url.lastIndexOf("-"); + + if (dotIndexOf < 0 & splitIndexOf < 0) { + return url + "-" + pageNumber; + } + + if (dotIndexOf < 0 && splitIndexOf > 0) { + return url.substring(0, splitIndexOf) + "-" + pageNumber; + } + + if (dotIndexOf > 0 && splitIndexOf < 0) { + return url.substring(0, dotIndexOf) + "-" + pageNumber + url.substring(dotIndexOf); + } + + //if (dotIndexOf > 0 && spitIndexOf >0){ + return url.substring(0, splitIndexOf) + "-" + pageNumber + url.substring(dotIndexOf); + } + + public static void main(String[] args) { + + System.out.println(replacePageNumber("/aa/bb/all-1", 123)); + System.out.println(replacePageNumber("/aa/bb/cc", 123)); + System.out.println(replacePageNumber("/aa/bb/cc.html", 123)); + System.out.println(replacePageNumber("/aa/bb/cc-33-44.html", 123)); + System.out.println(replacePageNumber("/aa/bb/cc-333.html", 123)); + System.out.println(replacePageNumber("/aa/bb/cc-1.html", 123)); + System.out.println(replacePageNumber("/aa/bb/cc-31", 123)); + System.out.println(replacePageNumber("/aa/bb/cc-", 123)); + + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/directive/StrSplit.java b/jpress-commons/src/main/java/io/jpress/commons/directive/StrSplit.java index 7178e0791dc5b87462ff1ef4fc9ffaf2905d9723..9d1808fa57ed17d67fc0eb9a9205fc9d08885e19 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/directive/StrSplit.java +++ b/jpress-commons/src/main/java/io/jpress/commons/directive/StrSplit.java @@ -1,32 +1,32 @@ -package io.jpress.commons.directive; - -import com.jfinal.template.Env; -import com.jfinal.template.io.Writer; -import com.jfinal.template.stat.Scope; -import io.jboot.utils.StrUtil; -import io.jboot.web.directive.annotation.JFinalDirective; -import io.jboot.web.directive.base.JbootDirectiveBase; - -import java.util.Set; - -@JFinalDirective("strSplit") -public class StrSplit extends JbootDirectiveBase { - @Override - public void onRender(Env env, Scope scope, Writer writer) { - String orginalStr = getPara(0, scope); - if (StrUtil.isBlank(orginalStr)) { - return; - } - - String splitStr = getPara(1, scope, ","); - Set strs = StrUtil.splitToSet(orginalStr,splitStr); - - scope.setLocal("strs", strs); - renderBody(env, scope, writer); - } - - @Override - public boolean hasEnd() { - return true; - } -} +package io.jpress.commons.directive; + +import com.jfinal.template.Env; +import com.jfinal.template.io.Writer; +import com.jfinal.template.stat.Scope; +import io.jboot.utils.StrUtil; +import io.jboot.web.directive.annotation.JFinalDirective; +import io.jboot.web.directive.base.JbootDirectiveBase; + +import java.util.Set; + +@JFinalDirective("strSplit") +public class StrSplit extends JbootDirectiveBase { + @Override + public void onRender(Env env, Scope scope, Writer writer) { + String orginalStr = getPara(0, scope); + if (StrUtil.isBlank(orginalStr)) { + return; + } + + String splitStr = getPara(1, scope, ","); + Set strs = StrUtil.splitToSet(orginalStr,splitStr); + + scope.setLocal("strs", strs); + renderBody(env, scope, writer); + } + + @Override + public boolean hasEnd() { + return true; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/email/AliyunEmailSender.java b/jpress-commons/src/main/java/io/jpress/commons/email/AliyunEmailSender.java index 8c1958c735e2362599804067a2220d7c0d9dcef8..9dbb68bbd54d1962695d91c78b04109e8686be48 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/email/AliyunEmailSender.java +++ b/jpress-commons/src/main/java/io/jpress/commons/email/AliyunEmailSender.java @@ -1,37 +1,37 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.email; - -import com.jfinal.log.Log; - -/** - * 暂未实现 - */ -public class AliyunEmailSender implements EmailSender { - private static final Log logger = Log.getLog(AliyunEmailSender.class); - - /** - * 文档: - * https://help.aliyun.com/document_detail/directmail/api-reference/sendmail - * -related/SingleSendMail.html?spm=5176.docdirectmail/api-reference/ - * sendmail-related/BatchSendMail.6.118.Qd9yth - */ - @Override - public boolean send(Email email) { - - return false; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.email; + +import com.jfinal.log.Log; + +/** + * 暂未实现 + */ +public class AliyunEmailSender implements EmailSender { + private static final Log logger = Log.getLog(AliyunEmailSender.class); + + /** + * 文档: + * https://help.aliyun.com/document_detail/directmail/api-reference/sendmail + * -related/SingleSendMail.html?spm=5176.docdirectmail/api-reference/ + * sendmail-related/BatchSendMail.6.118.Qd9yth + */ + @Override + public boolean send(Email email) { + + return false; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/email/Email.java b/jpress-commons/src/main/java/io/jpress/commons/email/Email.java index c6a136f2ad623be5142d8b70a3d9034bab8b1d79..3d231adbad1f21a7dd0818c125da418acb466db0 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/email/Email.java +++ b/jpress-commons/src/main/java/io/jpress/commons/email/Email.java @@ -1,105 +1,105 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.email; - -import com.jfinal.log.Log; -import io.jpress.JPressConsts; -import io.jpress.JPressOptions; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Package io.jpress.commons.email - */ - -public class Email { - - private static final Log LOG = Log.getLog(Email.class); - - private String[] to = null; - private String[] cc = null; - private String subject = null; - private String content = null; - - public static Email create() { - return new Email(); - } - - public Email to(String... toEmails) { - this.to = toEmails; - return this; - } - - public Email cc(String... ccEmails) { - this.cc = ccEmails; - return this; - } - - public Email subject(String subject) { - this.subject = subject; - return this; - } - - public Email content(String content) { - this.content = content; - return this; - } - - public String[] getTo() { - return to; - } - - public String[] getCc() { - return cc; - } - - public String getSubject() { - return subject; - } - - public String getContent() { - return content; - } - - public void send() { - send(new SimpleEmailSender()); - } - - public void send(EmailSender sender) { - try { - sender.send(this); - } catch (Throwable ex) { - LOG.error(ex.toString(), ex); - } - } - - public static void main(String[] args) { - - JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_ENABLE, "true"); - JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_SMTP, "smtp.qq.com"); - JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_ACCOUNT, "noreply@jeepress.com"); - JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_PASSWORD, "****"); - JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_SSL_ENABLE, "true"); - - - Email.create() - .subject("这是邮件标题") - .content("这是邮件内容~~~~~~") - .to("1506615067@qq.com") - .send(); - } -} - +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.email; + +import com.jfinal.log.Log; +import io.jpress.JPressConsts; +import io.jpress.JPressOptions; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Package io.jpress.commons.email + */ + +public class Email { + + private static final Log LOG = Log.getLog(Email.class); + + private String[] to = null; + private String[] cc = null; + private String subject = null; + private String content = null; + + public static Email create() { + return new Email(); + } + + public Email to(String... toEmails) { + this.to = toEmails; + return this; + } + + public Email cc(String... ccEmails) { + this.cc = ccEmails; + return this; + } + + public Email subject(String subject) { + this.subject = subject; + return this; + } + + public Email content(String content) { + this.content = content; + return this; + } + + public String[] getTo() { + return to; + } + + public String[] getCc() { + return cc; + } + + public String getSubject() { + return subject; + } + + public String getContent() { + return content; + } + + public void send() { + send(new SimpleEmailSender()); + } + + public void send(EmailSender sender) { + try { + sender.send(this); + } catch (Throwable ex) { + LOG.error(ex.toString(), ex); + } + } + + public static void main(String[] args) { + + JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_ENABLE, "true"); + JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_SMTP, "smtp.qq.com"); + JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_ACCOUNT, "noreply@jeepress.com"); + JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_PASSWORD, "****"); + JPressOptions.set(JPressConsts.OPTION_CONNECTION_EMAIL_SSL_ENABLE, "true"); + + + Email.create() + .subject("这是邮件标题") + .content("这是邮件内容~~~~~~") + .to("1506615067@qq.com") + .send(); + } +} + diff --git a/jpress-commons/src/main/java/io/jpress/commons/email/EmailSender.java b/jpress-commons/src/main/java/io/jpress/commons/email/EmailSender.java index dce4b5f99751b387303b95a967fee708dda3f08a..87060a4321a468f17033afc694ce63ec474f3ec0 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/email/EmailSender.java +++ b/jpress-commons/src/main/java/io/jpress/commons/email/EmailSender.java @@ -1,22 +1,22 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.email; - -public interface EmailSender { - - public boolean send(Email email); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.email; + +public interface EmailSender { + + public boolean send(Email email); + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/email/SimpleEmailSender.java b/jpress-commons/src/main/java/io/jpress/commons/email/SimpleEmailSender.java index a4d25fb02b50dcc7054ddf5213d8019a8ed90d14..2ae2862a5e854cc1d82cdf6a95bcf99c0599c968 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/email/SimpleEmailSender.java +++ b/jpress-commons/src/main/java/io/jpress/commons/email/SimpleEmailSender.java @@ -1,152 +1,152 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.email; - -import com.jfinal.log.Log; -import io.jboot.utils.StrUtil; -import io.jpress.JPressConsts; -import io.jpress.JPressOptions; - -import javax.mail.*; -import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeUtility; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; - -public class SimpleEmailSender extends Authenticator implements EmailSender { - - private static final Log logger = Log.getLog(SimpleEmailSender.class); - - private String host; - private String name; - private String password; - private boolean useSSL = true; - private boolean enable = false; - - public SimpleEmailSender() { - this.host = JPressOptions.get(JPressConsts.OPTION_CONNECTION_EMAIL_SMTP); - this.name = JPressOptions.get(JPressConsts.OPTION_CONNECTION_EMAIL_ACCOUNT); - this.password = JPressOptions.get(JPressConsts.OPTION_CONNECTION_EMAIL_PASSWORD); - this.useSSL = JPressOptions.getAsBool(JPressConsts.OPTION_CONNECTION_EMAIL_SSL_ENABLE); - this.enable = JPressOptions.getAsBool(JPressConsts.OPTION_CONNECTION_EMAIL_ENABLE); - } - - private Message createMessage() { - - - Properties props = new Properties(); - - props.setProperty("mail.transport.protocol", "smtp"); - - props.setProperty("mail.smtp.auth", "true"); - props.setProperty("mail.smtp.host", host); - props.setProperty("mail.smtp.port", "25"); - - if (useSSL) { - props.put("mail.smtp.starttls.enable", "true"); - props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); - props.setProperty("mail.smtp.port", "465"); - } - - // error:javax.mail.MessagingException: 501 Syntax: HELO hostname - props.setProperty("mail.smtp.localhost", "127.0.0.1"); - - Session session = Session.getInstance(props, this); - Message message = new MimeMessage(session); - - try { - message.setFrom(new InternetAddress(MimeUtility.encodeText(name) + "<" + name + ">")); - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - return message; - } - - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(name, password); - } - - private static Address[] toAddress(String... emails) { - if (emails == null || emails.length == 0) { - return null; - } - - Set

    addresses = new HashSet<>(); - for (String email : emails) { - if (StrUtil.isNotBlank(email)) { - try { - addresses.add(new InternetAddress(email)); - } catch (AddressException e) { - continue; - } - } - } - return addresses.toArray(new Address[0]); - } - - @Override - public boolean send(Email email) { - if (enable == false) { - //do nothing - return false; - } - - Message message = createMessage(); - try { - message.setSubject(email.getSubject()); - message.setContent(email.getContent(), "text/html;charset=utf-8"); - - message.setRecipients(Message.RecipientType.TO, toAddress(email.getTo())); - message.setRecipients(Message.RecipientType.CC, toAddress(email.getCc())); - - Transport.send(message); - - return true; - } catch (MessagingException e) { - logger.error("SimpleEmailSender send error", e); - } - - return false; - } - - public String getHost() { - return host; - } - - public String getName() { - return name; - } - - public String getPassword() { - return password; - } - - public boolean isUseSSL() { - return useSSL; - } - - public boolean isEnable() { - return enable; - } - - public boolean isConfigOk() { - return StrUtil.areNotEmpty(host, name, password); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.email; + +import com.jfinal.log.Log; +import io.jboot.utils.StrUtil; +import io.jpress.JPressConsts; +import io.jpress.JPressOptions; + +import javax.mail.*; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +public class SimpleEmailSender extends Authenticator implements EmailSender { + + private static final Log logger = Log.getLog(SimpleEmailSender.class); + + private String host; + private String name; + private String password; + private boolean useSSL = true; + private boolean enable = false; + + public SimpleEmailSender() { + this.host = JPressOptions.get(JPressConsts.OPTION_CONNECTION_EMAIL_SMTP); + this.name = JPressOptions.get(JPressConsts.OPTION_CONNECTION_EMAIL_ACCOUNT); + this.password = JPressOptions.get(JPressConsts.OPTION_CONNECTION_EMAIL_PASSWORD); + this.useSSL = JPressOptions.getAsBool(JPressConsts.OPTION_CONNECTION_EMAIL_SSL_ENABLE); + this.enable = JPressOptions.getAsBool(JPressConsts.OPTION_CONNECTION_EMAIL_ENABLE); + } + + private Message createMessage() { + + + Properties props = new Properties(); + + props.setProperty("mail.transport.protocol", "smtp"); + + props.setProperty("mail.smtp.auth", "true"); + props.setProperty("mail.smtp.host", host); + props.setProperty("mail.smtp.port", "25"); + + if (useSSL) { + props.put("mail.smtp.starttls.enable", "true"); + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.setProperty("mail.smtp.port", "465"); + } + + // error:javax.mail.MessagingException: 501 Syntax: HELO hostname + props.setProperty("mail.smtp.localhost", "127.0.0.1"); + + Session session = Session.getInstance(props, this); + Message message = new MimeMessage(session); + + try { + message.setFrom(new InternetAddress(MimeUtility.encodeText(name) + "<" + name + ">")); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return message; + } + + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(name, password); + } + + private static Address[] toAddress(String... emails) { + if (emails == null || emails.length == 0) { + return null; + } + + Set

    addresses = new HashSet<>(); + for (String email : emails) { + if (StrUtil.isNotBlank(email)) { + try { + addresses.add(new InternetAddress(email)); + } catch (AddressException e) { + continue; + } + } + } + return addresses.toArray(new Address[0]); + } + + @Override + public boolean send(Email email) { + if (enable == false) { + //do nothing + return false; + } + + Message message = createMessage(); + try { + message.setSubject(email.getSubject()); + message.setContent(email.getContent(), "text/html;charset=utf-8"); + + message.setRecipients(Message.RecipientType.TO, toAddress(email.getTo())); + message.setRecipients(Message.RecipientType.CC, toAddress(email.getCc())); + + Transport.send(message); + + return true; + } catch (MessagingException e) { + logger.error("SimpleEmailSender send error", e); + } + + return false; + } + + public String getHost() { + return host; + } + + public String getName() { + return name; + } + + public String getPassword() { + return password; + } + + public boolean isUseSSL() { + return useSSL; + } + + public boolean isEnable() { + return enable; + } + + public boolean isConfigOk() { + return StrUtil.areNotEmpty(host, name, password); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/layer/SortKit.java b/jpress-commons/src/main/java/io/jpress/commons/layer/SortKit.java index 1636af78ad0fb7eb53612c2ff093c1257729b8ce..56115ed6d9c5475792a6019f67cb88f676fe8c65 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/layer/SortKit.java +++ b/jpress-commons/src/main/java/io/jpress/commons/layer/SortKit.java @@ -1,103 +1,103 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.layer; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 用于分层排序 或 用于进行树分层 - * @Package io.jpress.commons.layer - */ -public class SortKit { - - public static void fillParentAndChild(List models) { - if (models == null || models.size() == 0) { - return; - } - for (M child : models) { - M parent = getParent(models, child); - if (parent != null) { - child.setParent(parent); - if (parent.getChilds() == null || !parent.getChilds().contains(child)) { - parent.addChild(child); - } - } - } - } - - private static M getParent(List models, M child) { - for (M m : models) { - if (child.getParentId() != null && child.getParentId().equals(m.getId())) { - return m; - } - } - return null; - } - - public static void toLayer(List models) { - if (models == null || models.isEmpty()) { - return; - } - toTree(models); - List layerModelList = new ArrayList<>(); - treeToLayer(models, layerModelList); - models.clear(); - models.addAll(layerModelList); - } - - private static void treeToLayer(List treeList, List layerList) { - if (treeList == null || treeList.isEmpty()) { - return; - } - - for (M model : treeList) { - layerList.add(model); - treeToLayer(model.getChilds(), layerList); - } - } - - - public static void toTree(List models) { - if (models == null || models.isEmpty()) { - return; - } - List temp = new ArrayList<>(models); - models.clear(); - for (M model : temp) { - if (model.isTop()) { - model.setLayerNumber(0); - fillChild(model, temp); - models.add(model); - } - } - } - - private static void fillChild(M parent, List models) { - for (M model : models) { - if (parent.getId().equals(model.getParentId())) { - model.setParent(parent); - model.setLayerNumber(parent.getLayerNumber() + 1); - if (parent.getChilds() == null || !parent.getChilds().contains(model)) { - parent.addChild(model); - } - fillChild(model, models); - } - } - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.layer; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 用于分层排序 或 用于进行树分层 + * @Package io.jpress.commons.layer + */ +public class SortKit { + + public static void fillParentAndChild(List models) { + if (models == null || models.size() == 0) { + return; + } + for (M child : models) { + M parent = getParent(models, child); + if (parent != null) { + child.setParent(parent); + if (parent.getChilds() == null || !parent.getChilds().contains(child)) { + parent.addChild(child); + } + } + } + } + + private static M getParent(List models, M child) { + for (M m : models) { + if (child.getParentId() != null && child.getParentId().equals(m.getId())) { + return m; + } + } + return null; + } + + public static void toLayer(List models) { + if (models == null || models.isEmpty()) { + return; + } + toTree(models); + List layerModelList = new ArrayList<>(); + treeToLayer(models, layerModelList); + models.clear(); + models.addAll(layerModelList); + } + + private static void treeToLayer(List treeList, List layerList) { + if (treeList == null || treeList.isEmpty()) { + return; + } + + for (M model : treeList) { + layerList.add(model); + treeToLayer(model.getChilds(), layerList); + } + } + + + public static void toTree(List models) { + if (models == null || models.isEmpty()) { + return; + } + List temp = new ArrayList<>(models); + models.clear(); + for (M model : temp) { + if (model.isTop()) { + model.setLayerNumber(0); + fillChild(model, temp); + models.add(model); + } + } + } + + private static void fillChild(M parent, List models) { + for (M model : models) { + if (parent.getId().equals(model.getParentId())) { + model.setParent(parent); + model.setLayerNumber(parent.getLayerNumber() + 1); + if (parent.getChilds() == null || !parent.getChilds().contains(model)) { + parent.addChild(model); + } + fillChild(model, models); + } + } + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/layer/SortModel.java b/jpress-commons/src/main/java/io/jpress/commons/layer/SortModel.java index 33e11c204590a722d5ccdb53855b81f3b96937ec..dd7330899d43719b23cda90956601bd837e6efe2 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/layer/SortModel.java +++ b/jpress-commons/src/main/java/io/jpress/commons/layer/SortModel.java @@ -1,50 +1,50 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.layer; - - -import java.util.List; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 用于可以排序和父子分类等模型 - * @Package io.jpress.commons.layer - */ -public interface SortModel { - - public boolean isTop(); - - public Long getId(); - - public Long getParentId(); - - public void setParent(M parent); - - public M getParent(); - - public void setChilds(List childs); - - public void addChild(M child); - - public List getChilds(); - - public void setLayerNumber(int layerNumber); - - public int getLayerNumber(); - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.layer; + + +import java.util.List; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 用于可以排序和父子分类等模型 + * @Package io.jpress.commons.layer + */ +public interface SortModel { + + public boolean isTop(); + + public Long getId(); + + public Long getParentId(); + + public void setParent(M parent); + + public M getParent(); + + public void setChilds(List childs); + + public void addChild(M child); + + public List getChilds(); + + public void setLayerNumber(int layerNumber); + + public int getLayerNumber(); + + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/Oauth2Controller.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/Oauth2Controller.java index c38ce725293a1a10c4ad560c8a6bbeef775ef03c..af35464b0cc6f9c50fdf08665427d781ecaaf876 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/Oauth2Controller.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/Oauth2Controller.java @@ -1,91 +1,91 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2; - -import io.jboot.utils.StrUtil; -import io.jboot.web.controller.JbootController; - -public abstract class Oauth2Controller extends JbootController { - - // www.xxx.com/xxx/qq - // www.xxx.com/xxx/weibo - public void index() { - - String para = getPara(); - if (StrUtil.isBlank(para)) { - renderError(404); - return; - } - - OauthConnector connector = onConnectorGet(para); - - // 不支持此 connectior - if (connector == null) { - renderError(404); - return; - } - - String state = StrUtil.uuid(); - String url = connector.getAuthorizeUrl(state); - - setSessionAttr("oauth_state", state); - redirect(url); - } - - // www.xxx.com/xxx/callback/qq - // www.xxx.com/xxx/callback/weibo - public void callback() { - String sessionState = getSessionAttr("oauth_state"); - String state = getPara("state"); - - if (!sessionState.equals(state)) { - onAuthorizeError("state not validate"); - return; - } - - String code = getPara("code"); - if (null == code || "".equals(code.trim())) { - onAuthorizeError("can't get code"); - return; - } - - String processerName = getPara(); - OauthConnector connector = onConnectorGet(processerName); - - OauthUser ouser = null; - try { - ouser = connector.getUser(code); - } catch (Exception e) { - onAuthorizeError("get oauth user exception:" + e.getMessage()); - return; - } - - if (ouser == null) { - onAuthorizeError("can't get user info!"); - return; - } - - onAuthorizeSuccess(ouser); - - } - - public abstract void onAuthorizeSuccess(OauthUser oauthUser); - - public abstract void onAuthorizeError(String errorMessage); - - public abstract OauthConnector onConnectorGet(String para); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2; + +import io.jboot.utils.StrUtil; +import io.jboot.web.controller.JbootController; + +public abstract class Oauth2Controller extends JbootController { + + // www.xxx.com/xxx/qq + // www.xxx.com/xxx/weibo + public void index() { + + String para = getPara(); + if (StrUtil.isBlank(para)) { + renderError(404); + return; + } + + OauthConnector connector = onConnectorGet(para); + + // 不支持此 connectior + if (connector == null) { + renderError(404); + return; + } + + String state = StrUtil.uuid(); + String url = connector.getAuthorizeUrl(state); + + setSessionAttr("oauth_state", state); + redirect(url); + } + + // www.xxx.com/xxx/callback/qq + // www.xxx.com/xxx/callback/weibo + public void callback() { + String sessionState = getSessionAttr("oauth_state"); + String state = getPara("state"); + + if (!sessionState.equals(state)) { + onAuthorizeError("state not validate"); + return; + } + + String code = getPara("code"); + if (null == code || "".equals(code.trim())) { + onAuthorizeError("can't get code"); + return; + } + + String processerName = getPara(); + OauthConnector connector = onConnectorGet(processerName); + + OauthUser ouser = null; + try { + ouser = connector.getUser(code); + } catch (Exception e) { + onAuthorizeError("get oauth user exception:" + e.getMessage()); + return; + } + + if (ouser == null) { + onAuthorizeError("can't get user info!"); + return; + } + + onAuthorizeSuccess(ouser); + + } + + public abstract void onAuthorizeSuccess(OauthUser oauthUser); + + public abstract void onAuthorizeError(String errorMessage); + + public abstract OauthConnector onConnectorGet(String para); + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/OauthConnector.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/OauthConnector.java index a1188083d4b35546474f38f060833845e189ce0c..4defaca3142df8e205aba01fe9462fbda5f9ac7b 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/OauthConnector.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/OauthConnector.java @@ -1,108 +1,108 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2; - -import com.jfinal.log.Log; -import io.jboot.utils.HttpUtil; -import io.jboot.utils.RequestUtil; -import io.jboot.utils.StrUtil; -import io.jpress.JPressOptions; - -import java.util.Map; - -public abstract class OauthConnector { - - // 第一步,构建跳转的URL,跳转后用户登录成功,返回到callback url,并带上code - // 第二步,通过code,获取access token - // 第三步,通过 access token 获取用户的open_id - // 第四步,通过 open_id 获取用户信息 - private static final Log LOGGER = Log.getLog(OauthConnector.class); - - private String clientId; - private String clientSecret; - private String name; - private String redirectUri; - - public OauthConnector(String name, String appkey, String appSecret) { - this.clientId = appkey; - this.clientSecret = appSecret; - this.name = name; - String webDomain = JPressOptions.get("web_domain"); - if (StrUtil.isBlank(webDomain)) { - webDomain = RequestUtil.getBaseUrl(); - } - this.redirectUri = webDomain + "/oauth/callback/" + name; - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getRedirectUri() { - return redirectUri; - } - - public String getAuthorizeUrl(String state) { - return createAuthorizeUrl(state); - } - - protected String httpGet(String url) { - try { - return HttpUtil.httpGet(url); - } catch (Exception e) { - LOGGER.error("httpGet error", e); - } - return null; - } - - protected String httpPost(String url, Map params) { - try { - return HttpUtil.httpPost(url, params); - } catch (Exception e) { - LOGGER.error("httpGet error", e); - } - return null; - } - - public abstract String createAuthorizeUrl(String state); - - protected abstract OauthUser getOauthUser(String code); - - public OauthUser getUser(String code) { - return getOauthUser(code); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2; + +import com.jfinal.log.Log; +import io.jboot.utils.HttpUtil; +import io.jboot.utils.RequestUtil; +import io.jboot.utils.StrUtil; +import io.jpress.JPressOptions; + +import java.util.Map; + +public abstract class OauthConnector { + + // 第一步,构建跳转的URL,跳转后用户登录成功,返回到callback url,并带上code + // 第二步,通过code,获取access token + // 第三步,通过 access token 获取用户的open_id + // 第四步,通过 open_id 获取用户信息 + private static final Log LOGGER = Log.getLog(OauthConnector.class); + + private String clientId; + private String clientSecret; + private String name; + private String redirectUri; + + public OauthConnector(String name, String appkey, String appSecret) { + this.clientId = appkey; + this.clientSecret = appSecret; + this.name = name; + String webDomain = JPressOptions.get("web_domain"); + if (StrUtil.isBlank(webDomain)) { + webDomain = RequestUtil.getBaseUrl(); + } + this.redirectUri = webDomain + "/oauth/callback/" + name; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRedirectUri() { + return redirectUri; + } + + public String getAuthorizeUrl(String state) { + return createAuthorizeUrl(state); + } + + protected String httpGet(String url) { + try { + return HttpUtil.httpGet(url); + } catch (Exception e) { + LOGGER.error("httpGet error", e); + } + return null; + } + + protected String httpPost(String url, Map params) { + try { + return HttpUtil.httpPost(url, params); + } catch (Exception e) { + LOGGER.error("httpGet error", e); + } + return null; + } + + public abstract String createAuthorizeUrl(String state); + + protected abstract OauthUser getOauthUser(String code); + + public OauthUser getUser(String code) { + return getOauthUser(code); + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/OauthUser.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/OauthUser.java index c1cefb9be0eeaff88e23e3eb9060fe2841f9a410..4ac32521ca42d1b823892810e13826e488ac4911 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/OauthUser.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/OauthUser.java @@ -1,74 +1,74 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2; - -import java.io.Serializable; - -public class OauthUser implements Serializable { - - public static final String GENDER_MALE = "male"; - public static final String GENDER_FEMALE = "female"; - public static final String GENDER_UNKNOW = "unknow"; - - private static final long serialVersionUID = 1L; - - private String openId; - private String nickname; - private String avatar; - private String gender; // male/female/unknow - private String source; // 来源 - - public String getOpenId() { - return openId; - } - - public void setOpenId(String openId) { - this.openId = openId; - } - - public String getNickname() { - return nickname; - } - - public void setNickname(String nickname) { - this.nickname = nickname; - } - - public String getAvatar() { - return avatar; - } - - public void setAvatar(String avatar) { - this.avatar = avatar; - } - - public String getGender() { - return gender; - } - - public void setGender(String gender) { - this.gender = gender; - } - - public String getSource() { - return source; - } - - public void setSource(String source) { - this.source = source; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2; + +import java.io.Serializable; + +public class OauthUser implements Serializable { + + public static final String GENDER_MALE = "male"; + public static final String GENDER_FEMALE = "female"; + public static final String GENDER_UNKNOW = "unknow"; + + private static final long serialVersionUID = 1L; + + private String openId; + private String nickname; + private String avatar; + private String gender; // male/female/unknow + private String source; // 来源 + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/DingdingConnector.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/DingdingConnector.java index 42b844b255131f3f437374fd8939b1c68133cae6..01c0d5ad98e8f2d4ec810a779db9033c5bd5a9ae 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/DingdingConnector.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/DingdingConnector.java @@ -1,107 +1,107 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2.connector; - -import com.alibaba.fastjson.JSONObject; -import io.jpress.commons.oauth2.OauthConnector; -import io.jpress.commons.oauth2.OauthUser; - -import java.util.HashMap; -import java.util.Map; - -public class DingdingConnector extends OauthConnector { - - public DingdingConnector(String appkey, String appSecret) { - super("dingding", appkey, appSecret); - } - - @Override - public String createAuthorizeUrl(String state) { - //https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=APPID&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=REDIRECT_URI - StringBuilder sb = new StringBuilder("https://oapi.dingtalk.com/connect/oauth2/sns_authorize?"); - sb.append("scope=user"); - sb.append("&appid=" + getClientId()); - sb.append("&redirect_uri=" + getRedirectUri()); - sb.append("&response_type=code"); - sb.append("&state=" + state); - - return sb.toString(); - } - - @Override - protected OauthUser getOauthUser(String code) { - String accessToken = getAccessToken(code); - - JSONObject result = getPersistentCode(code, accessToken); - - String snsToken = getSnsToken(accessToken, result.getString("openid"), result.getString("persistent_code")); - - //https://oapi.dingtalk.com/sns/getuserinfo?sns_token=SNS_TOKEN - String url = "https://oapi.dingtalk.com/sns/getuserinfo?sns_token=" + snsToken; - - String httpString = httpGet(url); - JSONObject json = JSONObject.parseObject(httpString); - JSONObject userInfo = json.getJSONObject("user_info"); - OauthUser user = new OauthUser(); - user.setOpenId(userInfo.getString("openid")); - user.setNickname(userInfo.getString("nick")); - user.setSource(getName()); - - return user; - } - - protected String getAccessToken(String code) { - - StringBuilder urlBuilder = new StringBuilder("https://oapi.dingtalk.com/sns/gettoken?"); - urlBuilder.append("appid=" + getClientId()); - urlBuilder.append("&appsecret=" + getClientSecret()); - - String url = urlBuilder.toString(); - - String httpString = httpGet(url); - JSONObject json = JSONObject.parseObject(httpString); - return json.getString("access_token"); - } - - protected JSONObject getPersistentCode(String code, String access_token) { - //https://oapi.dingtalk.com/sns/get_persistent_code?access_token=ACCESS_TOKEN - StringBuilder urlBuilder = new StringBuilder("https://oapi.dingtalk.com/sns/get_persistent_code?"); - urlBuilder.append("access_token=" + access_token); - String url = urlBuilder.toString(); - - Map param = new HashMap<>(); - param.put("tmp_auth_code", code); - - String httpString = httpPost(url, param); - JSONObject json = JSONObject.parseObject(httpString); - return json; - } - - protected String getSnsToken(String access_token, String openId, String persistentCode) { - //https://oapi.dingtalk.com/sns/get_sns_token?access_token=ACCESS_TOKEN - StringBuilder urlBuilder = new StringBuilder("https://oapi.dingtalk.com/sns/get_sns_token?"); - urlBuilder.append("access_token=" + access_token); - String url = urlBuilder.toString(); - - Map param = new HashMap<>(); - param.put("openid", openId); - param.put("persistent_code", persistentCode); - - String httpString = httpPost(url, param); - JSONObject json = JSONObject.parseObject(httpString); - return json.getString("sns_token"); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2.connector; + +import com.alibaba.fastjson.JSONObject; +import io.jpress.commons.oauth2.OauthConnector; +import io.jpress.commons.oauth2.OauthUser; + +import java.util.HashMap; +import java.util.Map; + +public class DingdingConnector extends OauthConnector { + + public DingdingConnector(String appkey, String appSecret) { + super("dingding", appkey, appSecret); + } + + @Override + public String createAuthorizeUrl(String state) { + //https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=APPID&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=REDIRECT_URI + StringBuilder sb = new StringBuilder("https://oapi.dingtalk.com/connect/oauth2/sns_authorize?"); + sb.append("scope=user"); + sb.append("&appid=" + getClientId()); + sb.append("&redirect_uri=" + getRedirectUri()); + sb.append("&response_type=code"); + sb.append("&state=" + state); + + return sb.toString(); + } + + @Override + protected OauthUser getOauthUser(String code) { + String accessToken = getAccessToken(code); + + JSONObject result = getPersistentCode(code, accessToken); + + String snsToken = getSnsToken(accessToken, result.getString("openid"), result.getString("persistent_code")); + + //https://oapi.dingtalk.com/sns/getuserinfo?sns_token=SNS_TOKEN + String url = "https://oapi.dingtalk.com/sns/getuserinfo?sns_token=" + snsToken; + + String httpString = httpGet(url); + JSONObject json = JSONObject.parseObject(httpString); + JSONObject userInfo = json.getJSONObject("user_info"); + OauthUser user = new OauthUser(); + user.setOpenId(userInfo.getString("openid")); + user.setNickname(userInfo.getString("nick")); + user.setSource(getName()); + + return user; + } + + protected String getAccessToken(String code) { + + StringBuilder urlBuilder = new StringBuilder("https://oapi.dingtalk.com/sns/gettoken?"); + urlBuilder.append("appid=" + getClientId()); + urlBuilder.append("&appsecret=" + getClientSecret()); + + String url = urlBuilder.toString(); + + String httpString = httpGet(url); + JSONObject json = JSONObject.parseObject(httpString); + return json.getString("access_token"); + } + + protected JSONObject getPersistentCode(String code, String access_token) { + //https://oapi.dingtalk.com/sns/get_persistent_code?access_token=ACCESS_TOKEN + StringBuilder urlBuilder = new StringBuilder("https://oapi.dingtalk.com/sns/get_persistent_code?"); + urlBuilder.append("access_token=" + access_token); + String url = urlBuilder.toString(); + + Map param = new HashMap<>(); + param.put("tmp_auth_code", code); + + String httpString = httpPost(url, param); + JSONObject json = JSONObject.parseObject(httpString); + return json; + } + + protected String getSnsToken(String access_token, String openId, String persistentCode) { + //https://oapi.dingtalk.com/sns/get_sns_token?access_token=ACCESS_TOKEN + StringBuilder urlBuilder = new StringBuilder("https://oapi.dingtalk.com/sns/get_sns_token?"); + urlBuilder.append("access_token=" + access_token); + String url = urlBuilder.toString(); + + Map param = new HashMap<>(); + param.put("openid", openId); + param.put("persistent_code", persistentCode); + + String httpString = httpPost(url, param); + JSONObject json = JSONObject.parseObject(httpString); + return json.getString("sns_token"); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/GithubConnector.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/GithubConnector.java index 6ce29d9e9b4380ba9ad16c31bb6038e7ef6e1384..04164a3d1ace537038326a0fbe498d2e732ee323 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/GithubConnector.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/GithubConnector.java @@ -1,73 +1,73 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2.connector; - -import com.alibaba.fastjson.JSONObject; -import io.jpress.commons.oauth2.OauthConnector; -import io.jpress.commons.oauth2.OauthUser; - -public class GithubConnector extends OauthConnector { - - public GithubConnector(String appkey, String appSecret) { - super("github", appkey, appSecret); - } - - @Override - public String createAuthorizeUrl(String state) { - StringBuilder sb = new StringBuilder("https://github.com/login/oauth/authorize?"); - sb.append("scope=user"); - sb.append("&client_id=" + getClientId()); - sb.append("&redirect_uri=" + getRedirectUri()); - sb.append("&state=" + state); - - return sb.toString(); - } - - @Override - protected OauthUser getOauthUser(String code) { - String accessToken = getAccessToken(code); - - String url = "https://api.github.com/user?access_token=" + accessToken; - - String httpString = httpGet(url); - JSONObject json = JSONObject.parseObject(httpString); - - OauthUser user = new OauthUser(); - user.setAvatar(json.getString("avatar_url")); - user.setOpenId(json.getString("id")); - user.setNickname(json.getString("login")); - user.setSource(getName()); - - return user; - } - - protected String getAccessToken(String code) { - - StringBuilder urlBuilder = new StringBuilder("https://github.com/login/oauth/access_token?"); - urlBuilder.append("client_id=" + getClientId()); - urlBuilder.append("&client_secret=" + getClientSecret()); - urlBuilder.append("&code=" + code); - - String url = urlBuilder.toString(); - - String httpString = httpGet(url); -// JSONObject json = JSONObject.parseObject(httpString); -// return json.getString("access_token"); - - // access_token=b34db140be5ed745a0e8a07f9897d9ee1d8c432c&scope=user&token_type=bearer - return httpString.substring(httpString.indexOf("=") + 1, httpString.indexOf("&")); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2.connector; + +import com.alibaba.fastjson.JSONObject; +import io.jpress.commons.oauth2.OauthConnector; +import io.jpress.commons.oauth2.OauthUser; + +public class GithubConnector extends OauthConnector { + + public GithubConnector(String appkey, String appSecret) { + super("github", appkey, appSecret); + } + + @Override + public String createAuthorizeUrl(String state) { + StringBuilder sb = new StringBuilder("https://github.com/login/oauth/authorize?"); + sb.append("scope=user"); + sb.append("&client_id=" + getClientId()); + sb.append("&redirect_uri=" + getRedirectUri()); + sb.append("&state=" + state); + + return sb.toString(); + } + + @Override + protected OauthUser getOauthUser(String code) { + String accessToken = getAccessToken(code); + + String url = "https://api.github.com/user?access_token=" + accessToken; + + String httpString = httpGet(url); + JSONObject json = JSONObject.parseObject(httpString); + + OauthUser user = new OauthUser(); + user.setAvatar(json.getString("avatar_url")); + user.setOpenId(json.getString("id")); + user.setNickname(json.getString("login")); + user.setSource(getName()); + + return user; + } + + protected String getAccessToken(String code) { + + StringBuilder urlBuilder = new StringBuilder("https://github.com/login/oauth/access_token?"); + urlBuilder.append("client_id=" + getClientId()); + urlBuilder.append("&client_secret=" + getClientSecret()); + urlBuilder.append("&code=" + code); + + String url = urlBuilder.toString(); + + String httpString = httpGet(url); +// JSONObject json = JSONObject.parseObject(httpString); +// return json.getString("access_token"); + + // access_token=b34db140be5ed745a0e8a07f9897d9ee1d8c432c&scope=user&token_type=bearer + return httpString.substring(httpString.indexOf("=") + 1, httpString.indexOf("&")); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/OSChinaConnector.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/OSChinaConnector.java index beadccef5a31da1d0aa50df8cba7c5161cdf1a2f..e604d4fdf213f0164227a4ca2ffc6173a86b8e41 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/OSChinaConnector.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/OSChinaConnector.java @@ -1,104 +1,104 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2.connector; - -import com.alibaba.fastjson.JSONObject; -import io.jboot.utils.StrUtil; -import io.jpress.commons.oauth2.OauthConnector; -import io.jpress.commons.oauth2.OauthUser; - -public class OSChinaConnector extends OauthConnector { - - public OSChinaConnector(String appkey, String appSecret) { - super("oschina", appkey, appSecret); - } - - // DOC : http://www.oschina.net/openapi/ - - // public OSChinaConnector() { - // setClientId(OptionQuery.findValue("oauth2_oschina_appkey")); - // setClientSecret(OptionQuery.findValue("oauth2_oschina_appsecret")); - // setName("oschina"); - // } - - /** - * doc: http://www.oschina.net/openapi/docs/oauth2_authorize - */ - @Override - public String createAuthorizeUrl(String state) { - - StringBuilder urlBuilder = new StringBuilder("http://www.oschina.net/action/oauth2/authorize?"); - urlBuilder.append("response_type=code"); - urlBuilder.append("&client_id=" + getClientId()); - urlBuilder.append("&redirect_uri=" + getRedirectUri()); - urlBuilder.append("&state=" + state); - - return urlBuilder.toString(); - } - - protected String getAccessToken(String code) { - - StringBuilder urlBuilder = new StringBuilder("http://www.oschina.net/action/openapi/token?"); - urlBuilder.append("grant_type=authorization_code"); - urlBuilder.append("&dataType=json"); - urlBuilder.append("&client_id=" + getClientId()); - urlBuilder.append("&client_secret=" + getClientSecret()); - urlBuilder.append("&redirect_uri=" + getRedirectUri()); - urlBuilder.append("&code=" + code); - - String url = urlBuilder.toString(); - - - String httpString = httpGet(url); - // {"access_token":"07a2aeb2-0790-4a36-ae24-40b90c4fcfc1", - // "refresh_token":"bfd67382-f740-4735-b7f0-86fb9a2e49dc", - // "uid":111634, - // "token_type":"bearer", - // "expires_in":604799} - - if (StrUtil.isBlank(httpString)) { - return null; - } - - JSONObject json = JSONObject.parseObject(httpString); - return json.getString("access_token"); - } - - @Override - protected OauthUser getOauthUser(String code) { - - String accessToken = getAccessToken(code); - - String url = "http://www.oschina.net/action/openapi/user?access_token=" + accessToken + "&dataType=json"; - - String httpString = httpGet(url); - // {"gender":"male","name":"michaely","location":"北京 朝阳","id":111634, - // "avatar":"http://static.oschina.net/uploads/user/55/111634_50.jpg?t=1414374101000", - // "email":"fuhai999@gmail.com","url":"http://my.oschina.net/yangfuhai"} - - JSONObject json = JSONObject.parseObject(httpString); - - OauthUser user = new OauthUser(); - user.setAvatar(json.getString("avatar")); - user.setOpenId(json.getString("id")); - user.setNickname(json.getString("name")); - user.setGender(json.getString("gender")); - user.setSource(getName()); - - return user; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2.connector; + +import com.alibaba.fastjson.JSONObject; +import io.jboot.utils.StrUtil; +import io.jpress.commons.oauth2.OauthConnector; +import io.jpress.commons.oauth2.OauthUser; + +public class OSChinaConnector extends OauthConnector { + + public OSChinaConnector(String appkey, String appSecret) { + super("oschina", appkey, appSecret); + } + + // DOC : http://www.oschina.net/openapi/ + + // public OSChinaConnector() { + // setClientId(OptionQuery.findValue("oauth2_oschina_appkey")); + // setClientSecret(OptionQuery.findValue("oauth2_oschina_appsecret")); + // setName("oschina"); + // } + + /** + * doc: http://www.oschina.net/openapi/docs/oauth2_authorize + */ + @Override + public String createAuthorizeUrl(String state) { + + StringBuilder urlBuilder = new StringBuilder("http://www.oschina.net/action/oauth2/authorize?"); + urlBuilder.append("response_type=code"); + urlBuilder.append("&client_id=" + getClientId()); + urlBuilder.append("&redirect_uri=" + getRedirectUri()); + urlBuilder.append("&state=" + state); + + return urlBuilder.toString(); + } + + protected String getAccessToken(String code) { + + StringBuilder urlBuilder = new StringBuilder("http://www.oschina.net/action/openapi/token?"); + urlBuilder.append("grant_type=authorization_code"); + urlBuilder.append("&dataType=json"); + urlBuilder.append("&client_id=" + getClientId()); + urlBuilder.append("&client_secret=" + getClientSecret()); + urlBuilder.append("&redirect_uri=" + getRedirectUri()); + urlBuilder.append("&code=" + code); + + String url = urlBuilder.toString(); + + + String httpString = httpGet(url); + // {"access_token":"07a2aeb2-0790-4a36-ae24-40b90c4fcfc1", + // "refresh_token":"bfd67382-f740-4735-b7f0-86fb9a2e49dc", + // "uid":111634, + // "token_type":"bearer", + // "expires_in":604799} + + if (StrUtil.isBlank(httpString)) { + return null; + } + + JSONObject json = JSONObject.parseObject(httpString); + return json.getString("access_token"); + } + + @Override + protected OauthUser getOauthUser(String code) { + + String accessToken = getAccessToken(code); + + String url = "http://www.oschina.net/action/openapi/user?access_token=" + accessToken + "&dataType=json"; + + String httpString = httpGet(url); + // {"gender":"male","name":"michaely","location":"北京 朝阳","id":111634, + // "avatar":"http://static.oschina.net/uploads/user/55/111634_50.jpg?t=1414374101000", + // "email":"fuhai999@gmail.com","url":"http://my.oschina.net/yangfuhai"} + + JSONObject json = JSONObject.parseObject(httpString); + + OauthUser user = new OauthUser(); + user.setAvatar(json.getString("avatar")); + user.setOpenId(json.getString("id")); + user.setNickname(json.getString("name")); + user.setGender(json.getString("gender")); + user.setSource(getName()); + + return user; + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/QQConnector.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/QQConnector.java index ec95325f7cb377ca78660b932318c6eb144db707..134a9841aff27ba61077bb80309e737973527ad5 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/QQConnector.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/QQConnector.java @@ -1,127 +1,127 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2.connector; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import io.jboot.utils.StrUtil; -import io.jpress.commons.oauth2.OauthConnector; -import io.jpress.commons.oauth2.OauthUser; - -public class QQConnector extends OauthConnector { - - public QQConnector(String appkey, String appSecret) { - super("qq", appkey, appSecret); - } - - /** - * http://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code - */ - @Override - public String createAuthorizeUrl(String state) { - - StringBuilder sb = new StringBuilder("https://graph.qq.com/oauth2.0/authorize?"); - sb.append("response_type=code"); - sb.append("&client_id=" + getClientId()); - sb.append("&redirect_uri=" + getRedirectUri()); - sb.append("&state=" + state); - - return sb.toString(); - } - - protected String getAccessToken(String code) { - - StringBuilder sb = new StringBuilder("https://graph.qq.com/oauth2.0/token?"); - sb.append("grant_type=authorization_code"); - sb.append("&code=" + code); - sb.append("&client_id=" + getClientId()); - sb.append("&client_secret=" + getClientSecret()); - sb.append("&redirect_uri=" + getRedirectUri()); - - String httpString = httpGet(sb.toString()); - - //callback( {"error":100010,"error_description":"redirect uri is illegal"} ); - //access_token=2D6FE76*****24AB&expires_in=7776000&refresh_token=7CD56****218 - - if (StrUtil.isBlank(httpString)) { - return null; - } - - if (httpString.contains("\"error\":")) { - throw new IllegalStateException(httpString); - } - - return httpString.substring(httpString.indexOf("=") + 1, httpString.indexOf("&")); - } - - protected String getOpenId(String accessToken, String code) { - - StringBuilder sb = new StringBuilder("https://graph.qq.com/oauth2.0/me?"); - sb.append("access_token=" + accessToken); - - String httpString = httpGet(sb.toString()); - // callback( - // {"client_id":"10***65","openid":"F8D32108D*****D"} - // ); - - if (StrUtil.isBlank(httpString)) { - return null; - } - - if (httpString.contains("\"error\":")) { - throw new IllegalStateException(httpString); - } - - return httpString.substring(httpString.lastIndexOf(":") + 2, httpString.lastIndexOf("\"")); - } - - @Override - protected OauthUser getOauthUser(String code) { - String accessToken = getAccessToken(code); - if (StrUtil.isBlank(accessToken)) { - return null; - } - String openId = getOpenId(accessToken, code); - if (StrUtil.isBlank(openId)) { - return null; - } - - StringBuilder sb = new StringBuilder("https://graph.qq.com/user/get_user_info?"); - sb.append("access_token=" + accessToken); - sb.append("&oauth_consumer_key=" + getClientId()); - sb.append("&openid=" + openId); - sb.append("&format=format"); - - String httpString = httpGet(sb.toString()); - - if (StrUtil.isBlank(httpString)) { - return null; - } - - JSONObject json = JSON.parseObject(httpString); - String gender = json.getString("gender"); - OauthUser user = new OauthUser(); - - user.setAvatar(json.getString("figureurl_2")); - user.setNickname(json.getString("nickname")); - user.setOpenId(openId); - user.setSource(getName()); - user.setGender("男".equals(gender) ? OauthUser.GENDER_MALE : ("女".equals(gender) ? OauthUser.GENDER_FEMALE : OauthUser.GENDER_UNKNOW)); - - return user; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2.connector; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import io.jboot.utils.StrUtil; +import io.jpress.commons.oauth2.OauthConnector; +import io.jpress.commons.oauth2.OauthUser; + +public class QQConnector extends OauthConnector { + + public QQConnector(String appkey, String appSecret) { + super("qq", appkey, appSecret); + } + + /** + * http://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code + */ + @Override + public String createAuthorizeUrl(String state) { + + StringBuilder sb = new StringBuilder("https://graph.qq.com/oauth2.0/authorize?"); + sb.append("response_type=code"); + sb.append("&client_id=" + getClientId()); + sb.append("&redirect_uri=" + getRedirectUri()); + sb.append("&state=" + state); + + return sb.toString(); + } + + protected String getAccessToken(String code) { + + StringBuilder sb = new StringBuilder("https://graph.qq.com/oauth2.0/token?"); + sb.append("grant_type=authorization_code"); + sb.append("&code=" + code); + sb.append("&client_id=" + getClientId()); + sb.append("&client_secret=" + getClientSecret()); + sb.append("&redirect_uri=" + getRedirectUri()); + + String httpString = httpGet(sb.toString()); + + //callback( {"error":100010,"error_description":"redirect uri is illegal"} ); + //access_token=2D6FE76*****24AB&expires_in=7776000&refresh_token=7CD56****218 + + if (StrUtil.isBlank(httpString)) { + return null; + } + + if (httpString.contains("\"error\":")) { + throw new IllegalStateException(httpString); + } + + return httpString.substring(httpString.indexOf("=") + 1, httpString.indexOf("&")); + } + + protected String getOpenId(String accessToken, String code) { + + StringBuilder sb = new StringBuilder("https://graph.qq.com/oauth2.0/me?"); + sb.append("access_token=" + accessToken); + + String httpString = httpGet(sb.toString()); + // callback( + // {"client_id":"10***65","openid":"F8D32108D*****D"} + // ); + + if (StrUtil.isBlank(httpString)) { + return null; + } + + if (httpString.contains("\"error\":")) { + throw new IllegalStateException(httpString); + } + + return httpString.substring(httpString.lastIndexOf(":") + 2, httpString.lastIndexOf("\"")); + } + + @Override + protected OauthUser getOauthUser(String code) { + String accessToken = getAccessToken(code); + if (StrUtil.isBlank(accessToken)) { + return null; + } + String openId = getOpenId(accessToken, code); + if (StrUtil.isBlank(openId)) { + return null; + } + + StringBuilder sb = new StringBuilder("https://graph.qq.com/user/get_user_info?"); + sb.append("access_token=" + accessToken); + sb.append("&oauth_consumer_key=" + getClientId()); + sb.append("&openid=" + openId); + sb.append("&format=format"); + + String httpString = httpGet(sb.toString()); + + if (StrUtil.isBlank(httpString)) { + return null; + } + + JSONObject json = JSON.parseObject(httpString); + String gender = json.getString("gender"); + OauthUser user = new OauthUser(); + + user.setAvatar(json.getString("figureurl_2")); + user.setNickname(json.getString("nickname")); + user.setOpenId(openId); + user.setSource(getName()); + user.setGender("男".equals(gender) ? OauthUser.GENDER_MALE : ("女".equals(gender) ? OauthUser.GENDER_FEMALE : OauthUser.GENDER_UNKNOW)); + + return user; + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/WechatConnector.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/WechatConnector.java index e2ce3509a5ac0e809f6ed36a02b9f544b44f974e..403351f7edb373b0d8a5ecb83fabc242dd060433 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/WechatConnector.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/WechatConnector.java @@ -1,120 +1,120 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2.connector; - -import com.alibaba.fastjson.JSONObject; -import io.jpress.commons.oauth2.OauthConnector; -import io.jpress.commons.oauth2.OauthUser; - -public class WechatConnector extends OauthConnector { - - public WechatConnector(String appkey, String appSecret) { - super("wechat", appkey, appSecret); - } - - // DOC - // https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&id=open1419316505 - - // public WechatConnector() { - // setClientId(OptionQuery.findValue("oauth2_wechat_appkey")); - // setClientSecret(OptionQuery.findValue("oauth2_wechat_appsecret")); - // setName("wechat"); - // } - - @Override - public String createAuthorizeUrl(String state) { - - // https://open.weixin.qq.com/connect/qrconnect? - // appid=APPID - // &redirect_uri=REDIRECT_URI - // &response_type=code - // &scope=SCOPE - // &state=STATE#wechat_redirect - - StringBuilder urlBuilder = new StringBuilder("https://open.weixin.qq.com/connect/qrconnect?"); - urlBuilder.append("response_type=code"); - urlBuilder.append("&scope=snsapi_login"); - urlBuilder.append("&appid=" + getClientId()); - urlBuilder.append("&redirect_uri=" + getRedirectUri()); - urlBuilder.append("&state=" + state); - urlBuilder.append("#wechat_redirect"); - - return urlBuilder.toString(); - } - - protected JSONObject getAccessToken(String code) { - - // https://api.weixin.qq.com/sns/oauth2/access_token? - // appid=APPID - // &secret=SECRET - // &code=CODE - // &grant_type=authorization_code - - StringBuilder urlBuilder = new StringBuilder("https://api.weixin.qq.com/sns/oauth2/access_token?"); - urlBuilder.append("grant_type=authorization_code"); - urlBuilder.append("&appid=" + getClientId()); - urlBuilder.append("&secret=" + getClientSecret()); - urlBuilder.append("&code=" + code); - - String url = urlBuilder.toString(); - - String httpString = httpGet(url); - - /** - * { "access_token":"ACCESS_TOKEN", "expires_in":7200, - * "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE", - * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" } - */ - - return JSONObject.parseObject(httpString); - } - - @Override - protected OauthUser getOauthUser(String code) { - - JSONObject tokenJson = getAccessToken(code); - String accessToken = tokenJson.getString("access_token"); - String openId = tokenJson.getString("openid"); - - // https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID - - String url = "https://api.weixin.qq.com/sns/userinfo?" + "access_token=" + accessToken + "&openid=" + openId; - - String httpString = httpGet(url); - - /** - * { "openid":"OPENID", "nickname":"NICKNAME", "sex":1, - * "province":"PROVINCE", "city":"CITY", "country":"COUNTRY", - * "headimgurl": - * "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0", - * "privilege":[ "PRIVILEGE1", "PRIVILEGE2" ], "unionid": - * " o6_bmasdasdsad6_2sgVt7hMZOPfL" } - */ - - OauthUser user = new OauthUser(); - JSONObject json = JSONObject.parseObject(httpString); - user.setAvatar(json.getString("headimgurl")); - user.setNickname(json.getString("nickname")); - user.setOpenId(openId); - int sex = json.getIntValue("sex"); - user.setGender(sex == 1 ? "male" : "female"); - - user.setSource(getName()); - - return user; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2.connector; + +import com.alibaba.fastjson.JSONObject; +import io.jpress.commons.oauth2.OauthConnector; +import io.jpress.commons.oauth2.OauthUser; + +public class WechatConnector extends OauthConnector { + + public WechatConnector(String appkey, String appSecret) { + super("wechat", appkey, appSecret); + } + + // DOC + // https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&id=open1419316505 + + // public WechatConnector() { + // setClientId(OptionQuery.findValue("oauth2_wechat_appkey")); + // setClientSecret(OptionQuery.findValue("oauth2_wechat_appsecret")); + // setName("wechat"); + // } + + @Override + public String createAuthorizeUrl(String state) { + + // https://open.weixin.qq.com/connect/qrconnect? + // appid=APPID + // &redirect_uri=REDIRECT_URI + // &response_type=code + // &scope=SCOPE + // &state=STATE#wechat_redirect + + StringBuilder urlBuilder = new StringBuilder("https://open.weixin.qq.com/connect/qrconnect?"); + urlBuilder.append("response_type=code"); + urlBuilder.append("&scope=snsapi_login"); + urlBuilder.append("&appid=" + getClientId()); + urlBuilder.append("&redirect_uri=" + getRedirectUri()); + urlBuilder.append("&state=" + state); + urlBuilder.append("#wechat_redirect"); + + return urlBuilder.toString(); + } + + protected JSONObject getAccessToken(String code) { + + // https://api.weixin.qq.com/sns/oauth2/access_token? + // appid=APPID + // &secret=SECRET + // &code=CODE + // &grant_type=authorization_code + + StringBuilder urlBuilder = new StringBuilder("https://api.weixin.qq.com/sns/oauth2/access_token?"); + urlBuilder.append("grant_type=authorization_code"); + urlBuilder.append("&appid=" + getClientId()); + urlBuilder.append("&secret=" + getClientSecret()); + urlBuilder.append("&code=" + code); + + String url = urlBuilder.toString(); + + String httpString = httpGet(url); + + /** + * { "access_token":"ACCESS_TOKEN", "expires_in":7200, + * "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE", + * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" } + */ + + return JSONObject.parseObject(httpString); + } + + @Override + protected OauthUser getOauthUser(String code) { + + JSONObject tokenJson = getAccessToken(code); + String accessToken = tokenJson.getString("access_token"); + String openId = tokenJson.getString("openid"); + + // https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID + + String url = "https://api.weixin.qq.com/sns/userinfo?" + "access_token=" + accessToken + "&openid=" + openId; + + String httpString = httpGet(url); + + /** + * { "openid":"OPENID", "nickname":"NICKNAME", "sex":1, + * "province":"PROVINCE", "city":"CITY", "country":"COUNTRY", + * "headimgurl": + * "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0", + * "privilege":[ "PRIVILEGE1", "PRIVILEGE2" ], "unionid": + * " o6_bmasdasdsad6_2sgVt7hMZOPfL" } + */ + + OauthUser user = new OauthUser(); + JSONObject json = JSONObject.parseObject(httpString); + user.setAvatar(json.getString("headimgurl")); + user.setNickname(json.getString("nickname")); + user.setOpenId(openId); + int sex = json.getIntValue("sex"); + user.setGender(sex == 1 ? "male" : "female"); + + user.setSource(getName()); + + return user; + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/WeiboConnector.java b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/WeiboConnector.java index e1d18c0a7392e5b29742c1c86651a4479a539cc7..5707a013c40e29514405b2a2a66bf3e508e70412 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/WeiboConnector.java +++ b/jpress-commons/src/main/java/io/jpress/commons/oauth2/connector/WeiboConnector.java @@ -1,88 +1,88 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.oauth2.connector; - -import com.alibaba.fastjson.JSONObject; -import io.jboot.utils.StrUtil; -import io.jpress.commons.oauth2.OauthConnector; -import io.jpress.commons.oauth2.OauthUser; - -import java.util.HashMap; -import java.util.Map; - -public class WeiboConnector extends OauthConnector { - - public WeiboConnector(String appkey, String appSecret) { - super("weibo", appkey, appSecret); - } - - @Override - public String createAuthorizeUrl(String state) { - - StringBuilder urlBuilder = new StringBuilder("https://api.weibo.com/oauth2/authorize?"); - urlBuilder.append("scope=email"); - urlBuilder.append("&client_id=" + getClientId()); - urlBuilder.append("&redirect_uri=" + getRedirectUri()); - urlBuilder.append("&state=" + state); - - return urlBuilder.toString(); - } - - @Override - protected OauthUser getOauthUser(String code) { - - Map params = new HashMap<>(); - params.put("grant_type", "authorization_code"); - params.put("client_id", getClientId()); - params.put("client_secret", getClientSecret()); - params.put("redirect_uri", getRedirectUri()); - params.put("code", code); - - String url = "https://api.weibo.com/oauth2/access_token"; - String httpString = httpPost(url, params); - - if (StrUtil.isBlank(httpString)) { - return null; - } - - JSONObject json = JSONObject.parseObject(httpString); - String accessToken = json.getString("access_token"); - String uid = json.getString("uid"); - - url = "https://api.weibo.com/2/users/show.json?" + "access_token=" + accessToken + "&uid=" + uid; - - httpString = httpGet(url); - json = JSONObject.parseObject(httpString); - - OauthUser user = new OauthUser(); - user.setAvatar(json.getString("avatar_large")); - user.setNickname(json.getString("screen_name")); - user.setOpenId(json.getString("id")); - user.setGender(genders.get(json.getString("gender"))); - user.setSource(getName()); - - return user; - } - - static Map genders = new HashMap(); - - static { - genders.put("m", "male"); - genders.put("f", "female"); - genders.put("n", "unkown"); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.oauth2.connector; + +import com.alibaba.fastjson.JSONObject; +import io.jboot.utils.StrUtil; +import io.jpress.commons.oauth2.OauthConnector; +import io.jpress.commons.oauth2.OauthUser; + +import java.util.HashMap; +import java.util.Map; + +public class WeiboConnector extends OauthConnector { + + public WeiboConnector(String appkey, String appSecret) { + super("weibo", appkey, appSecret); + } + + @Override + public String createAuthorizeUrl(String state) { + + StringBuilder urlBuilder = new StringBuilder("https://api.weibo.com/oauth2/authorize?"); + urlBuilder.append("scope=email"); + urlBuilder.append("&client_id=" + getClientId()); + urlBuilder.append("&redirect_uri=" + getRedirectUri()); + urlBuilder.append("&state=" + state); + + return urlBuilder.toString(); + } + + @Override + protected OauthUser getOauthUser(String code) { + + Map params = new HashMap<>(); + params.put("grant_type", "authorization_code"); + params.put("client_id", getClientId()); + params.put("client_secret", getClientSecret()); + params.put("redirect_uri", getRedirectUri()); + params.put("code", code); + + String url = "https://api.weibo.com/oauth2/access_token"; + String httpString = httpPost(url, params); + + if (StrUtil.isBlank(httpString)) { + return null; + } + + JSONObject json = JSONObject.parseObject(httpString); + String accessToken = json.getString("access_token"); + String uid = json.getString("uid"); + + url = "https://api.weibo.com/2/users/show.json?" + "access_token=" + accessToken + "&uid=" + uid; + + httpString = httpGet(url); + json = JSONObject.parseObject(httpString); + + OauthUser user = new OauthUser(); + user.setAvatar(json.getString("avatar_large")); + user.setNickname(json.getString("screen_name")); + user.setOpenId(json.getString("id")); + user.setGender(genders.get(json.getString("gender"))); + user.setSource(getName()); + + return user; + } + + static Map genders = new HashMap(); + + static { + genders.put("m", "male"); + genders.put("f", "female"); + genders.put("n", "unkown"); + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/AlipayPayConfig.java b/jpress-commons/src/main/java/io/jpress/commons/pay/AlipayPayConfig.java index 0c9be696720adbd83b7cbd2b43177a970ec59578..b951b3a6bdcedeac5fc426df5415889b653cf4ae 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/AlipayPayConfig.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/AlipayPayConfig.java @@ -1,109 +1,109 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -import com.egzosn.pay.ali.api.AliPayConfigStorage; -import com.egzosn.pay.common.util.sign.SignUtils; -import io.jboot.utils.StrUtil; -import io.jpress.JPressOptions; - -public class AlipayPayConfig extends PayConfigBase{ - - private boolean enable; - private String pid; - private String appid; - private String publicKey; - private String privateKey; - private String seller; - - - public AlipayPayConfig() { - super("alipay"); - setEnable(JPressOptions.getAsBool("alipay_pay_enable")); - setPid(JPressOptions.get("alipay_pay_pid")); - setAppid(JPressOptions.get("alipay_pay_appid")); - setPublicKey(JPressOptions.get("alipay_pay_publicKey")); - setPrivateKey(JPressOptions.get("alipay_pay_privateKey")); - setSeller(JPressOptions.get("alipay_pay_seller")); - } - - public boolean isConfigOk() { - return StrUtil.areNotEmpty(pid, appid, publicKey, privateKey, seller); - } - - public boolean isEnable() { - return enable; - } - - public void setEnable(boolean enable) { - this.enable = enable; - } - - public String getAppid() { - return appid; - } - - public void setAppid(String appid) { - this.appid = appid; - } - - public String getPid() { - return pid; - } - - public void setPid(String pid) { - this.pid = pid; - } - - public String getPublicKey() { - return publicKey; - } - - public void setPublicKey(String publicKey) { - this.publicKey = publicKey; - } - - public String getPrivateKey() { - return privateKey; - } - - public void setPrivateKey(String privateKey) { - this.privateKey = privateKey; - } - - public String getSeller() { - return seller; - } - - public void setSeller(String seller) { - this.seller = seller; - } - - public AliPayConfigStorage toConfigStorage() { - AliPayConfigStorage storage = new AliPayConfigStorage(); - storage.setPid(getPid()); - storage.setAppid(getAppid()); - storage.setKeyPublic(getPublicKey()); - storage.setKeyPrivate(getPrivateKey()); - storage.setSeller(getSeller()); - storage.setNotifyUrl(getCallbackUrl()); - storage.setReturnUrl(getReturnUrl()); - storage.setSignType(SignUtils.RSA2.name()); - storage.setInputCharset("utf-8"); - return storage; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +import com.egzosn.pay.ali.api.AliPayConfigStorage; +import com.egzosn.pay.common.util.sign.SignUtils; +import io.jboot.utils.StrUtil; +import io.jpress.JPressOptions; + +public class AlipayPayConfig extends PayConfigBase{ + + private boolean enable; + private String pid; + private String appid; + private String publicKey; + private String privateKey; + private String seller; + + + public AlipayPayConfig() { + super("alipay"); + setEnable(JPressOptions.getAsBool("alipay_pay_enable")); + setPid(JPressOptions.get("alipay_pay_pid")); + setAppid(JPressOptions.get("alipay_pay_appid")); + setPublicKey(JPressOptions.get("alipay_pay_publicKey")); + setPrivateKey(JPressOptions.get("alipay_pay_privateKey")); + setSeller(JPressOptions.get("alipay_pay_seller")); + } + + public boolean isConfigOk() { + return StrUtil.areNotEmpty(pid, appid, publicKey, privateKey, seller); + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getPublicKey() { + return publicKey; + } + + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } + + public String getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(String privateKey) { + this.privateKey = privateKey; + } + + public String getSeller() { + return seller; + } + + public void setSeller(String seller) { + this.seller = seller; + } + + public AliPayConfigStorage toConfigStorage() { + AliPayConfigStorage storage = new AliPayConfigStorage(); + storage.setPid(getPid()); + storage.setAppid(getAppid()); + storage.setKeyPublic(getPublicKey()); + storage.setKeyPrivate(getPrivateKey()); + storage.setSeller(getSeller()); + storage.setNotifyUrl(getCallbackUrl()); + storage.setReturnUrl(getReturnUrl()); + storage.setSignType(SignUtils.RSA2.name()); + storage.setInputCharset("utf-8"); + return storage; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/AlipayxPayConfig.java b/jpress-commons/src/main/java/io/jpress/commons/pay/AlipayxPayConfig.java index 8b1e7644c975028150e476ee29a20d16271558fb..13af152427593b6138c320fab69eac92e3530402 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/AlipayxPayConfig.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/AlipayxPayConfig.java @@ -1,63 +1,63 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -import io.jboot.utils.StrUtil; -import io.jpress.JPressOptions; - -public class AlipayxPayConfig { - - private boolean enable; - private String qrcode; - private String message; - - public AlipayxPayConfig() { - setEnable(JPressOptions.getAsBool("alipayx_pay_enable")); - setQrcode(JPressOptions.get("alipayx_pay_qrcode")); - setMessage(JPressOptions.get("alipayx_pay_message")); - } - - public boolean isConfigOk() { - return StrUtil.areNotEmpty(qrcode, message); - } - - public boolean isEnable() { - return enable; - } - - public void setEnable(boolean enable) { - this.enable = enable; - } - - public String getQrcode() { - return qrcode; - } - - public void setQrcode(String qrcode) { - this.qrcode = qrcode; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +import io.jboot.utils.StrUtil; +import io.jpress.JPressOptions; + +public class AlipayxPayConfig { + + private boolean enable; + private String qrcode; + private String message; + + public AlipayxPayConfig() { + setEnable(JPressOptions.getAsBool("alipayx_pay_enable")); + setQrcode(JPressOptions.get("alipayx_pay_qrcode")); + setMessage(JPressOptions.get("alipayx_pay_message")); + } + + public boolean isConfigOk() { + return StrUtil.areNotEmpty(qrcode, message); + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getQrcode() { + return qrcode; + } + + public void setQrcode(String qrcode) { + this.qrcode = qrcode; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + } \ No newline at end of file diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/PayConfigBase.java b/jpress-commons/src/main/java/io/jpress/commons/pay/PayConfigBase.java index d83dd403db9cc263efb8720db242d356afe85f8f..6e8628b6b1a3caed83a9f9b0ea834779ee49a611 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/PayConfigBase.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/PayConfigBase.java @@ -1,47 +1,47 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -import io.jpress.JPressOptions; - -public class PayConfigBase { - - private String callbackUrl; - - private String returnUrl; - - public PayConfigBase(String name) { - setCallbackUrl(JPressOptions.get("web_domain") + "/pay/callback/" + name); - setReturnUrl(JPressOptions.get("web_domain") + "/pay/back/" + name); - } - - public String getCallbackUrl() { - return callbackUrl; - } - - public void setCallbackUrl(String callbackUrl) { - this.callbackUrl = callbackUrl; - } - - public String getReturnUrl() { - return returnUrl; - } - - public void setReturnUrl(String returnUrl) { - this.returnUrl = returnUrl; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +import io.jpress.JPressOptions; + +public class PayConfigBase { + + private String callbackUrl; + + private String returnUrl; + + public PayConfigBase(String name) { + setCallbackUrl(JPressOptions.get("web_domain") + "/pay/callback/" + name); + setReturnUrl(JPressOptions.get("web_domain") + "/pay/back/" + name); + } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + + public String getReturnUrl() { + return returnUrl; + } + + public void setReturnUrl(String returnUrl) { + this.returnUrl = returnUrl; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/PayConfigUtil.java b/jpress-commons/src/main/java/io/jpress/commons/pay/PayConfigUtil.java index 0aae0188fcfb1c6148e62f7b5e4b8b6900a93ba2..2d2eed24ac1365c363e3de133ab440d716d7f6fa 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/PayConfigUtil.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/PayConfigUtil.java @@ -1,71 +1,71 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -import com.egzosn.pay.ali.api.AliPayService; -import com.egzosn.pay.paypal.api.PayPalPayService; -import com.egzosn.pay.wx.api.WxPayService; -import com.jfinal.core.Controller; - -public class PayConfigUtil { - - public static AlipayPayConfig getAlipayPayConfig() { - return new AlipayPayConfig(); - } - - public static AlipayxPayConfig getAlipayxPayConfig() { - return new AlipayxPayConfig(); - } - - public static WechatPayConfig getWechatPayConfig() { - return new WechatPayConfig(); - } - - public static WechatxPayConfig getWechatxPayConfig() { - return new WechatxPayConfig(); - } - - public static PaypalPayConfig getPaypalPayConfig() { - return new PaypalPayConfig(); - } - - - public static WxPayService getWxPayService() { - WechatPayConfig config = getWechatPayConfig(); - return config.isEnable() && config.isConfigOk() ? new WxPayService(config.toConfigStorage()) : null; - } - - - public static AliPayService getAlipayService() { - AlipayPayConfig config = getAlipayPayConfig(); - return config.isEnable() && config.isConfigOk() ? new AliPayService(config.toConfigStorage()) : null; - } - - - public static PayPalPayService getPayPalPayService() { - PaypalPayConfig config = getPaypalPayConfig(); - return config.isEnable() && config.isConfigOk() ? new PayPalPayService(config.toConfigStorage()) : null; - } - - public static void setConfigAttrs(Controller controller) { - controller.setAttr("alipayConfig", getAlipayPayConfig()); - controller.setAttr("alipayxConfig", getAlipayxPayConfig()); - controller.setAttr("wechatConfig", getWechatPayConfig()); - controller.setAttr("wechatxConfig", getWechatxPayConfig()); - controller.setAttr("paypalConfig", getPaypalPayConfig()); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +import com.egzosn.pay.ali.api.AliPayService; +import com.egzosn.pay.paypal.api.PayPalPayService; +import com.egzosn.pay.wx.api.WxPayService; +import com.jfinal.core.Controller; + +public class PayConfigUtil { + + public static AlipayPayConfig getAlipayPayConfig() { + return new AlipayPayConfig(); + } + + public static AlipayxPayConfig getAlipayxPayConfig() { + return new AlipayxPayConfig(); + } + + public static WechatPayConfig getWechatPayConfig() { + return new WechatPayConfig(); + } + + public static WechatxPayConfig getWechatxPayConfig() { + return new WechatxPayConfig(); + } + + public static PaypalPayConfig getPaypalPayConfig() { + return new PaypalPayConfig(); + } + + + public static WxPayService getWxPayService() { + WechatPayConfig config = getWechatPayConfig(); + return config.isEnable() && config.isConfigOk() ? new WxPayService(config.toConfigStorage()) : null; + } + + + public static AliPayService getAlipayService() { + AlipayPayConfig config = getAlipayPayConfig(); + return config.isEnable() && config.isConfigOk() ? new AliPayService(config.toConfigStorage()) : null; + } + + + public static PayPalPayService getPayPalPayService() { + PaypalPayConfig config = getPaypalPayConfig(); + return config.isEnable() && config.isConfigOk() ? new PayPalPayService(config.toConfigStorage()) : null; + } + + public static void setConfigAttrs(Controller controller) { + controller.setAttr("alipayConfig", getAlipayPayConfig()); + controller.setAttr("alipayxConfig", getAlipayxPayConfig()); + controller.setAttr("wechatConfig", getWechatPayConfig()); + controller.setAttr("wechatxConfig", getWechatxPayConfig()); + controller.setAttr("paypalConfig", getPaypalPayConfig()); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/PayStatus.java b/jpress-commons/src/main/java/io/jpress/commons/pay/PayStatus.java index ac8e288ccaef0a75ea577a9e7cbe9da0dc67657a..376f452ecbf00dc6c9f391ae29b81e8ec8790338 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/PayStatus.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/PayStatus.java @@ -1,154 +1,154 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -import org.apache.commons.lang3.StringUtils; - -/** - * @author michael - */ - -public enum PayStatus { - - - /** - * 未支付 或者 准备支付 - */ - UNPAY(1, "未支付"), - - /** - * 支付失败 - */ - FAILURE(2, "支付失败"), - - - /** - * 支付中,但是未支付成功,由用户进行标识 - */ - PAID_ALIPAYX(3, "支付宝转账中"), - PAID_WECHATX(4, "微信转账中"), - PAID_OFFLINE(5, "线下支付中"), - PAID_OTHER(6, "其他方式支付中"), - - - /** - * 以下都是支付成功的情况 - */ - SUCCESS_ALIPAY(10, "支付宝支付成功"), - SUCCESS_ALIPAYX(11, "支付宝转账成功"), - SUCCESS_WECHAT(12, "微信支付成功"), - SUCCESS_WECHATX(13, "微信转账成功"), - SUCCESS_AMOUNT(14, "余额支付成功"), - SUCCESS_PAYPAL(15, "PayPal支付成功"), - SUCCESS_OFFLINE(16, "下线支付成功"), - SUCCESS_OTHER(17, "其他方式支付成功"); - - /** - * 状态 - */ - private int status; - - /** - * 文本内容 - */ - private String text; - - PayStatus(int status, String text) { - this.status = status; - this.text = text; - } - - public int getStatus() { - return status; - } - - public void setStatus(int status) { - this.status = status; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public static PayStatus getByStatus(int status) { - for (PayStatus payStatus : values()) { - if (payStatus.status == status) { - return payStatus; - } - } - return null; - } - - public static PayStatus getSuccessStatusByType(PayType payType) { - switch (payType) { - case ALIPAY: - return SUCCESS_ALIPAY; - case ALIPAYX: - return SUCCESS_ALIPAYX; - case WECHAT: - return SUCCESS_WECHAT; - case WECHATX: - return SUCCESS_WECHATX; - case AMOUNT: - return SUCCESS_AMOUNT; - case PAYPAL: - return SUCCESS_PAYPAL; - case OFFLINE: - return SUCCESS_OFFLINE; - case OTHER: - return SUCCESS_OTHER; - default: - return null; - } - } - - - public static int getSuccessIntStatusByType(String type) { - PayStatus payStatus = PayStatus.getSuccessStatusByType(PayType.getByType(type)); - return payStatus.getStatus(); - } - - - public static PayStatus getPaidStatusByType(PayType payType) { - switch (payType) { - case ALIPAYX: - return PAID_ALIPAYX; - case WECHATX: - return PAID_WECHATX; - case OFFLINE: - return PAID_OFFLINE; - case OTHER: - return PAID_OTHER; - default: - return null; - } - } - - public static String getTextByInt(Integer status) { - if (status == null) { - return StringUtils.EMPTY; - } - PayStatus payStatus = getByStatus(status); - return payStatus != null ? payStatus.text : StringUtils.EMPTY; - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +import org.apache.commons.lang3.StringUtils; + +/** + * @author michael + */ + +public enum PayStatus { + + + /** + * 未支付 或者 准备支付 + */ + UNPAY(1, "未支付"), + + /** + * 支付失败 + */ + FAILURE(2, "支付失败"), + + + /** + * 支付中,但是未支付成功,由用户进行标识 + */ + PAID_ALIPAYX(3, "支付宝转账中"), + PAID_WECHATX(4, "微信转账中"), + PAID_OFFLINE(5, "线下支付中"), + PAID_OTHER(6, "其他方式支付中"), + + + /** + * 以下都是支付成功的情况 + */ + SUCCESS_ALIPAY(10, "支付宝支付成功"), + SUCCESS_ALIPAYX(11, "支付宝转账成功"), + SUCCESS_WECHAT(12, "微信支付成功"), + SUCCESS_WECHATX(13, "微信转账成功"), + SUCCESS_AMOUNT(14, "余额支付成功"), + SUCCESS_PAYPAL(15, "PayPal支付成功"), + SUCCESS_OFFLINE(16, "下线支付成功"), + SUCCESS_OTHER(17, "其他方式支付成功"); + + /** + * 状态 + */ + private int status; + + /** + * 文本内容 + */ + private String text; + + PayStatus(int status, String text) { + this.status = status; + this.text = text; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public static PayStatus getByStatus(int status) { + for (PayStatus payStatus : values()) { + if (payStatus.status == status) { + return payStatus; + } + } + return null; + } + + public static PayStatus getSuccessStatusByType(PayType payType) { + switch (payType) { + case ALIPAY: + return SUCCESS_ALIPAY; + case ALIPAYX: + return SUCCESS_ALIPAYX; + case WECHAT: + return SUCCESS_WECHAT; + case WECHATX: + return SUCCESS_WECHATX; + case AMOUNT: + return SUCCESS_AMOUNT; + case PAYPAL: + return SUCCESS_PAYPAL; + case OFFLINE: + return SUCCESS_OFFLINE; + case OTHER: + return SUCCESS_OTHER; + default: + return null; + } + } + + + public static int getSuccessIntStatusByType(String type) { + PayStatus payStatus = PayStatus.getSuccessStatusByType(PayType.getByType(type)); + return payStatus.getStatus(); + } + + + public static PayStatus getPaidStatusByType(PayType payType) { + switch (payType) { + case ALIPAYX: + return PAID_ALIPAYX; + case WECHATX: + return PAID_WECHATX; + case OFFLINE: + return PAID_OFFLINE; + case OTHER: + return PAID_OTHER; + default: + return null; + } + } + + public static String getTextByInt(Integer status) { + if (status == null) { + return StringUtils.EMPTY; + } + PayStatus payStatus = getByStatus(status); + return payStatus != null ? payStatus.text : StringUtils.EMPTY; + } + + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/PayType.java b/jpress-commons/src/main/java/io/jpress/commons/pay/PayType.java index a7909314e3eb5d502efe598b1d1593e4932d80bb..0342f6326f3825472d35db66d555a47fa56a4d12 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/PayType.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/PayType.java @@ -1,65 +1,65 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -public enum PayType { - - AMOUNT("amount", "余额支付"), - WECHAT("wechat", "微信在线支付"), - WECHATX("wechatx", "微信好友转账支付"), - ALIPAY("alipay", "支付宝在线支付"), - ALIPAYX("alipayx", "支付宝转账支付"), - PAYPAL("paypal", "PayPal在线支付"), - OFFLINE("offline", "线下支付"), - OTHER("other", "其他方式支付"), - UNKOWN("unkown", "未知"); - - - PayType(String type, String text) { - this.type = type; - this.text = text; - } - - - private String type; - private String text; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public static PayType getByType(String type) { - for (PayType payType : values()) { - if (payType.type.equals(type)) { - return payType; - } - } - return UNKOWN; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +public enum PayType { + + AMOUNT("amount", "余额支付"), + WECHAT("wechat", "微信在线支付"), + WECHATX("wechatx", "微信好友转账支付"), + ALIPAY("alipay", "支付宝在线支付"), + ALIPAYX("alipayx", "支付宝转账支付"), + PAYPAL("paypal", "PayPal在线支付"), + OFFLINE("offline", "线下支付"), + OTHER("other", "其他方式支付"), + UNKOWN("unkown", "未知"); + + + PayType(String type, String text) { + this.type = type; + this.text = text; + } + + + private String type; + private String text; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public static PayType getByType(String type) { + for (PayType payType : values()) { + if (payType.type.equals(type)) { + return payType; + } + } + return UNKOWN; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/PaypalPayConfig.java b/jpress-commons/src/main/java/io/jpress/commons/pay/PaypalPayConfig.java index 3a55037f227f5f95317a1436decaa4d3041a2a38..00ef95ffcababb3bc7240d9790d92644d86d9092 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/PaypalPayConfig.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/PaypalPayConfig.java @@ -1,73 +1,73 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -import com.egzosn.pay.paypal.api.PayPalConfigStorage; -import io.jboot.utils.StrUtil; -import io.jpress.JPressOptions; - -public class PaypalPayConfig extends PayConfigBase{ - - private boolean enable; - private String clientId; - private String clientSecret; - - public PaypalPayConfig() { - super("paypal"); - setEnable(JPressOptions.getAsBool("paypal_pay_enable")); - setClientId(JPressOptions.get("paypal_pay_clientid")); - setClientSecret(JPressOptions.get("paypal_pay_clientsecret")); - } - - public boolean isConfigOk() { - return StrUtil.areNotEmpty(clientId, clientSecret); - } - - public boolean isEnable() { - return enable; - } - - public void setEnable(boolean enable) { - this.enable = enable; - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } - - public PayPalConfigStorage toConfigStorage(){ - PayPalConfigStorage storage = new PayPalConfigStorage(); - storage.setClientID(getClientId()); - storage.setClientSecret(getClientSecret()); - storage.setNotifyUrl(getCallbackUrl()); - storage.setReturnUrl(getReturnUrl()); -// storage.setTest(true); - return storage; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +import com.egzosn.pay.paypal.api.PayPalConfigStorage; +import io.jboot.utils.StrUtil; +import io.jpress.JPressOptions; + +public class PaypalPayConfig extends PayConfigBase{ + + private boolean enable; + private String clientId; + private String clientSecret; + + public PaypalPayConfig() { + super("paypal"); + setEnable(JPressOptions.getAsBool("paypal_pay_enable")); + setClientId(JPressOptions.get("paypal_pay_clientid")); + setClientSecret(JPressOptions.get("paypal_pay_clientsecret")); + } + + public boolean isConfigOk() { + return StrUtil.areNotEmpty(clientId, clientSecret); + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public PayPalConfigStorage toConfigStorage(){ + PayPalConfigStorage storage = new PayPalConfigStorage(); + storage.setClientID(getClientId()); + storage.setClientSecret(getClientSecret()); + storage.setNotifyUrl(getCallbackUrl()); + storage.setReturnUrl(getReturnUrl()); +// storage.setTest(true); + return storage; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/WechatPayConfig.java b/jpress-commons/src/main/java/io/jpress/commons/pay/WechatPayConfig.java index b3054670b7f62dffbcbfcdaaf520390289e23f93..fb4df04305a4eebb578afcecb723c8010626db27 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/WechatPayConfig.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/WechatPayConfig.java @@ -1,118 +1,118 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -import com.egzosn.pay.common.util.sign.SignUtils; -import com.egzosn.pay.wx.api.WxPayConfigStorage; -import io.jboot.utils.StrUtil; -import io.jpress.JPressOptions; - -public class WechatPayConfig extends PayConfigBase { - - private boolean enable; - private String mchId; - private String appid; - private String publicKey; - private String privateKey; - - public WechatPayConfig() { - super("wechat"); - setEnable(JPressOptions.getAsBool("wechat_pay_enable")); - setMchId(JPressOptions.get("wechat_pay_mchId")); - setAppid(JPressOptions.get("wechat_pay_appid")); -// setPublicKey(JPressOptions.get("wechat_pay_publicKey")); - setPrivateKey(JPressOptions.get("wechat_pay_secretKey")); - } - - public boolean isConfigOk() { - return StrUtil.areNotEmpty(mchId, appid, privateKey); - } - - public boolean isEnable() { - return enable; - } - - public void setEnable(boolean enable) { - this.enable = enable; - } - - public String getAppid() { - return appid; - } - - public void setAppid(String appid) { - this.appid = appid; - } - - public String getMchId() { - return mchId; - } - - public void setMchId(String mchId) { - this.mchId = mchId; - } - - public String getPublicKey() { - return publicKey; - } - - public void setPublicKey(String publicKey) { - this.publicKey = publicKey; - } - - public String getPrivateKey() { - return privateKey; - } - - public void setPrivateKey(String privateKey) { - this.privateKey = privateKey; - } - - public WxPayConfigStorage toConfigStorage() { - WxPayConfigStorage storage = new WxPayConfigStorage(); - - storage.setMchId(getMchId()); - storage.setAppid(getAppid()); -// storage.setKeyPublic(getPublicKey()); -// storage.setSecretKey(getPrivateKey()); - storage.setKeyPrivate(getPrivateKey()); - storage.setNotifyUrl(getCallbackUrl()); - storage.setReturnUrl(getReturnUrl()); - storage.setSignType(SignUtils.MD5.name()); - storage.setInputCharset("utf-8"); - -// HttpConfigStorage httpConfigStorage = new HttpConfigStorage(); -// httpConfigStorage.setKeystore(WxPayController.class.getResourceAsStream("/证书文件")); -// httpConfigStorage.setStorePassword("证书密码"); -// //设置ssl证书对应的存储方式输入流,这里默认为文件地址 -// httpConfigStorage.setCertStoreType(CertStoreType.INPUT_STREAM); -// service = new WxPayService(wxPayConfigStorage, httpConfigStorage); - - return storage; - } - - @Override - public String toString() { - return "WechatPayConfig{" + - "enable=" + enable + - ", mchId='" + mchId + '\'' + - ", appid='" + appid + '\'' + - ", publicKey='" + publicKey + '\'' + - ", privateKey='" + privateKey + '\'' + - '}'; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +import com.egzosn.pay.common.util.sign.SignUtils; +import com.egzosn.pay.wx.api.WxPayConfigStorage; +import io.jboot.utils.StrUtil; +import io.jpress.JPressOptions; + +public class WechatPayConfig extends PayConfigBase { + + private boolean enable; + private String mchId; + private String appid; + private String publicKey; + private String privateKey; + + public WechatPayConfig() { + super("wechat"); + setEnable(JPressOptions.getAsBool("wechat_pay_enable")); + setMchId(JPressOptions.get("wechat_pay_mchId")); + setAppid(JPressOptions.get("wechat_pay_appid")); +// setPublicKey(JPressOptions.get("wechat_pay_publicKey")); + setPrivateKey(JPressOptions.get("wechat_pay_secretKey")); + } + + public boolean isConfigOk() { + return StrUtil.areNotEmpty(mchId, appid, privateKey); + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getMchId() { + return mchId; + } + + public void setMchId(String mchId) { + this.mchId = mchId; + } + + public String getPublicKey() { + return publicKey; + } + + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } + + public String getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(String privateKey) { + this.privateKey = privateKey; + } + + public WxPayConfigStorage toConfigStorage() { + WxPayConfigStorage storage = new WxPayConfigStorage(); + + storage.setMchId(getMchId()); + storage.setAppid(getAppid()); +// storage.setKeyPublic(getPublicKey()); +// storage.setSecretKey(getPrivateKey()); + storage.setKeyPrivate(getPrivateKey()); + storage.setNotifyUrl(getCallbackUrl()); + storage.setReturnUrl(getReturnUrl()); + storage.setSignType(SignUtils.MD5.name()); + storage.setInputCharset("utf-8"); + +// HttpConfigStorage httpConfigStorage = new HttpConfigStorage(); +// httpConfigStorage.setKeystore(WxPayController.class.getResourceAsStream("/证书文件")); +// httpConfigStorage.setStorePassword("证书密码"); +// //设置ssl证书对应的存储方式输入流,这里默认为文件地址 +// httpConfigStorage.setCertStoreType(CertStoreType.INPUT_STREAM); +// service = new WxPayService(wxPayConfigStorage, httpConfigStorage); + + return storage; + } + + @Override + public String toString() { + return "WechatPayConfig{" + + "enable=" + enable + + ", mchId='" + mchId + '\'' + + ", appid='" + appid + '\'' + + ", publicKey='" + publicKey + '\'' + + ", privateKey='" + privateKey + '\'' + + '}'; + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/pay/WechatxPayConfig.java b/jpress-commons/src/main/java/io/jpress/commons/pay/WechatxPayConfig.java index 0a9acd56065567000b5482657d297fcea4c5cb04..7ba5a6c6861b97c49852f4f9e50d56b00f2ee971 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/pay/WechatxPayConfig.java +++ b/jpress-commons/src/main/java/io/jpress/commons/pay/WechatxPayConfig.java @@ -1,63 +1,63 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.pay; - - -import io.jboot.utils.StrUtil; -import io.jpress.JPressOptions; - -public class WechatxPayConfig { - - private boolean enable; - private String qrcode; - private String message; - - public WechatxPayConfig() { - setEnable(JPressOptions.getAsBool("wechatx_pay_enable")); - setQrcode(JPressOptions.get("wechatx_pay_qrcode")); - setMessage(JPressOptions.get("wechatx_pay_message")); - } - - public boolean isConfigOk() { - return StrUtil.areNotEmpty(qrcode, message); - } - - public boolean isEnable() { - return enable; - } - - public void setEnable(boolean enable) { - this.enable = enable; - } - - public String getQrcode() { - return qrcode; - } - - public void setQrcode(String qrcode) { - this.qrcode = qrcode; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.pay; + + +import io.jboot.utils.StrUtil; +import io.jpress.JPressOptions; + +public class WechatxPayConfig { + + private boolean enable; + private String qrcode; + private String message; + + public WechatxPayConfig() { + setEnable(JPressOptions.getAsBool("wechatx_pay_enable")); + setQrcode(JPressOptions.get("wechatx_pay_qrcode")); + setMessage(JPressOptions.get("wechatx_pay_message")); + } + + public boolean isConfigOk() { + return StrUtil.areNotEmpty(qrcode, message); + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getQrcode() { + return qrcode; + } + + public void setQrcode(String qrcode) { + this.qrcode = qrcode; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/sms/AliyunSmsSender.java b/jpress-commons/src/main/java/io/jpress/commons/sms/AliyunSmsSender.java index 9b2f0db5001378b3604283d6434feb1627fd3270..66cebfe6729e78d17aa1ef7aaf3bdb7e5ced4b02 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/sms/AliyunSmsSender.java +++ b/jpress-commons/src/main/java/io/jpress/commons/sms/AliyunSmsSender.java @@ -1,142 +1,142 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.sms; - -import com.jfinal.kit.Base64Kit; -import com.jfinal.log.Log; -import io.jboot.utils.HttpUtil; -import io.jboot.utils.StrUtil; -import io.jpress.JPressConsts; -import io.jpress.JPressOptions; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.SimpleTimeZone; - -/** - * 阿里云短信发送 - * api 接口文档 :https://help.aliyun.com/document_detail/56189.html?spm=a2c4g.11186623.6.590.263891ebLwA3nl - */ -public class AliyunSmsSender implements SmsSender { - - private static final Log log = Log.getLog(AliyunSmsSender.class); - - @Override - public boolean send(SmsMessage sms) { - - String app_key = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_APPID); - String app_secret = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_APPSECRET); - - - Map params = new HashMap<>(); - params.put("AccessKeyId", app_key); - - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - df.setTimeZone(new SimpleTimeZone(0, "GMT")); - String timestamp = df.format(new Date()); - params.put("Timestamp", timestamp); - params.put("Format", "JSON"); - params.put("SignatureMethod", "HMAC-SHA1"); - params.put("SignatureVersion", "1.0"); - params.put("SignatureNonce", StrUtil.uuid()); - - - params.put("Action", "SendSms"); - params.put("Version", "2017-05-25"); - params.put("RegionId", "cn-hangzhou"); - params.put("PhoneNumbers", sms.getMobile()); - params.put("SignName", sms.getSign()); - params.put("TemplateCode", sms.getTemplate()); - - if (StrUtil.isNotBlank(sms.getCode())) { - params.put("TemplateParam", "{\"code\":" + sms.getCode() + "}"); - } - - try { - String url = doSignAndGetUrl(params, app_secret); - String content = HttpUtil.httpGet(url); - if (StrUtil.isNotBlank(content) && content.contains("\"Code\":\"OK\"")) { - return true; - } else { - log.error("aliyun sms send error : " + content); - } - } catch (Exception e) { - log.error("AliyunSmsSender exception", e); - } - - return false; - } - - public static String doSignAndGetUrl(Map params, String secret) throws Exception { - - java.util.TreeMap sortParas = new java.util.TreeMap<>(); - sortParas.putAll(params); - - - java.util.Iterator it = sortParas.keySet().iterator(); - StringBuilder sortQueryStringTmp = new StringBuilder(); - while (it.hasNext()) { - String key = it.next(); - sortQueryStringTmp.append("&").append(specialUrlEncode(key)).append("=").append(specialUrlEncode(params.get(key).toString())); - } - String sortedQueryString = sortQueryStringTmp.substring(1);// 去除第一个多余的&符号 - StringBuilder stringToSign = new StringBuilder(); - stringToSign.append("GET").append("&"); - stringToSign.append(specialUrlEncode("/")).append("&"); - stringToSign.append(specialUrlEncode(sortedQueryString)); - String sign = sign(secret + "&", stringToSign.toString()); - - - String signature = specialUrlEncode(sign); - return "http://dysmsapi.aliyuncs.com/?Signature=" + signature + sortQueryStringTmp; - } - - public static String specialUrlEncode(String value) throws Exception { - return java.net.URLEncoder.encode(value, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~"); - } - - public static String sign(String accessSecret, String stringToSign) throws Exception { - javax.crypto.Mac mac = javax.crypto.Mac.getInstance("HmacSHA1"); - mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes("UTF-8"), "HmacSHA1")); - byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); - return Base64Kit.encode(signData); -// return new sun.misc.BASE64Encoder().encode(signData); - } - - - public static void main(String[] args) { - - String app_key = ""; - String app_secret = ""; - - JPressOptions.set(JPressConsts.OPTION_CONNECTION_SMS_APPID, app_key); - JPressOptions.set(JPressConsts.OPTION_CONNECTION_SMS_APPSECRET, app_secret); - - SmsMessage sms = new SmsMessage(); - sms.setMobile("18611220000"); - sms.setTemplate("SMS_148593333"); - sms.setSign("JPress"); - sms.setCode("1234"); - - boolean sendOk = new AliyunSmsSender().send(sms); - - System.out.println(sendOk); - System.out.println("===============finished!==================="); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.sms; + +import com.jfinal.kit.Base64Kit; +import com.jfinal.log.Log; +import io.jboot.utils.HttpUtil; +import io.jboot.utils.StrUtil; +import io.jpress.JPressConsts; +import io.jpress.JPressOptions; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.SimpleTimeZone; + +/** + * 阿里云短信发送 + * api 接口文档 :https://help.aliyun.com/document_detail/56189.html?spm=a2c4g.11186623.6.590.263891ebLwA3nl + */ +public class AliyunSmsSender implements SmsSender { + + private static final Log log = Log.getLog(AliyunSmsSender.class); + + @Override + public boolean send(SmsMessage sms) { + + String app_key = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_APPID); + String app_secret = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_APPSECRET); + + + Map params = new HashMap<>(); + params.put("AccessKeyId", app_key); + + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + df.setTimeZone(new SimpleTimeZone(0, "GMT")); + String timestamp = df.format(new Date()); + params.put("Timestamp", timestamp); + params.put("Format", "JSON"); + params.put("SignatureMethod", "HMAC-SHA1"); + params.put("SignatureVersion", "1.0"); + params.put("SignatureNonce", StrUtil.uuid()); + + + params.put("Action", "SendSms"); + params.put("Version", "2017-05-25"); + params.put("RegionId", "cn-hangzhou"); + params.put("PhoneNumbers", sms.getMobile()); + params.put("SignName", sms.getSign()); + params.put("TemplateCode", sms.getTemplate()); + + if (StrUtil.isNotBlank(sms.getCode())) { + params.put("TemplateParam", "{\"code\":" + sms.getCode() + "}"); + } + + try { + String url = doSignAndGetUrl(params, app_secret); + String content = HttpUtil.httpGet(url); + if (StrUtil.isNotBlank(content) && content.contains("\"Code\":\"OK\"")) { + return true; + } else { + log.error("aliyun sms send error : " + content); + } + } catch (Exception e) { + log.error("AliyunSmsSender exception", e); + } + + return false; + } + + public static String doSignAndGetUrl(Map params, String secret) throws Exception { + + java.util.TreeMap sortParas = new java.util.TreeMap<>(); + sortParas.putAll(params); + + + java.util.Iterator it = sortParas.keySet().iterator(); + StringBuilder sortQueryStringTmp = new StringBuilder(); + while (it.hasNext()) { + String key = it.next(); + sortQueryStringTmp.append("&").append(specialUrlEncode(key)).append("=").append(specialUrlEncode(params.get(key).toString())); + } + String sortedQueryString = sortQueryStringTmp.substring(1);// 去除第一个多余的&符号 + StringBuilder stringToSign = new StringBuilder(); + stringToSign.append("GET").append("&"); + stringToSign.append(specialUrlEncode("/")).append("&"); + stringToSign.append(specialUrlEncode(sortedQueryString)); + String sign = sign(secret + "&", stringToSign.toString()); + + + String signature = specialUrlEncode(sign); + return "http://dysmsapi.aliyuncs.com/?Signature=" + signature + sortQueryStringTmp; + } + + public static String specialUrlEncode(String value) throws Exception { + return java.net.URLEncoder.encode(value, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~"); + } + + public static String sign(String accessSecret, String stringToSign) throws Exception { + javax.crypto.Mac mac = javax.crypto.Mac.getInstance("HmacSHA1"); + mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes("UTF-8"), "HmacSHA1")); + byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); + return Base64Kit.encode(signData); +// return new sun.misc.BASE64Encoder().encode(signData); + } + + + public static void main(String[] args) { + + String app_key = ""; + String app_secret = ""; + + JPressOptions.set(JPressConsts.OPTION_CONNECTION_SMS_APPID, app_key); + JPressOptions.set(JPressConsts.OPTION_CONNECTION_SMS_APPSECRET, app_secret); + + SmsMessage sms = new SmsMessage(); + sms.setMobile("18611220000"); + sms.setTemplate("SMS_148593333"); + sms.setSign("JPress"); + sms.setCode("1234"); + + boolean sendOk = new AliyunSmsSender().send(sms); + + System.out.println(sendOk); + System.out.println("===============finished!==================="); + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/sms/NonSmsSender.java b/jpress-commons/src/main/java/io/jpress/commons/sms/NonSmsSender.java index 6088a8ca73e62f30e4a70f417660877fc6d6aeda..8e627492f2596e1a2cb65661ecc36915752afca9 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/sms/NonSmsSender.java +++ b/jpress-commons/src/main/java/io/jpress/commons/sms/NonSmsSender.java @@ -1,31 +1,31 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.sms; - -/** - * 当 短信 功能关闭的时候 - * 通过 Factory 创建 Sender 返回此 Sender - */ -public class NonSmsSender implements SmsSender { - - - @Override - public boolean send(SmsMessage sms) { - return false; - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.sms; + +/** + * 当 短信 功能关闭的时候 + * 通过 Factory 创建 Sender 返回此 Sender + */ +public class NonSmsSender implements SmsSender { + + + @Override + public boolean send(SmsMessage sms) { + return false; + } + + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/sms/QCloudSmsSender.java b/jpress-commons/src/main/java/io/jpress/commons/sms/QCloudSmsSender.java index a2b96abc11b47c35cb23dacca1211efcac0d4aa7..ba78a038862a3df823c0d9fb09e4c837e4e64022 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/sms/QCloudSmsSender.java +++ b/jpress-commons/src/main/java/io/jpress/commons/sms/QCloudSmsSender.java @@ -1,100 +1,100 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.sms; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.jfinal.kit.HashKit; -import com.jfinal.kit.LogKit; -import io.jboot.utils.HttpUtil; -import io.jboot.utils.StrUtil; -import io.jpress.JPressConsts; -import io.jpress.JPressOptions; - -import java.util.Random; - -/** - * 腾讯云短信发送 - * api 接口文档 :https://cloud.tencent.com/document/product/382/5976 - */ -public class QCloudSmsSender implements SmsSender { - - private static final String SMS_JSON = "{\"ext\":\"\",\"extend\":\"\",\"params\":[\"{code}\",30],\"sig\":\"{sig}\",\"sign\":\"{sign}\",\"tel\":{\"mobile\":\"{mobile}\",\"nationcode\":\"86\"},\"time\":{time},\"tpl_id\":{tpl_id}}"; - private static final String SMS_NO_CODE_JSON = "{\"ext\":\"\",\"extend\":\"\",\"params\":[30],\"sig\":\"{sig}\",\"sign\":\"{sign}\",\"tel\":{\"mobile\":\"{mobile}\",\"nationcode\":\"86\"},\"time\":{time},\"tpl_id\":{tpl_id}}"; - - - @Override - public boolean send(SmsMessage sms) { - - String app_key = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_APPID); - String app_secret = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_APPSECRET); - - String random = new Random().nextInt(1000000) + ""; - String time = System.currentTimeMillis() / 1000 + ""; - - String srcStr = "appkey=" + app_secret + "&random=" + random + "&time=" + time + "&mobile=" + sms.getMobile(); - String sig = HashKit.sha256(srcStr); - - boolean hasCode = StrUtil.isNotBlank(sms.getCode()); - - String postContent = (hasCode ? SMS_JSON.replace("{code}", sms.getCode()) : SMS_NO_CODE_JSON) - .replace("{sig}", sig) - .replace("{sign}", sms.getSign()) - .replace("{mobile}", sms.getMobile()) - .replace("{time}", time) - .replace("{tpl_id}", sms.getTemplate()); - - String url = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms?sdkappid=" + app_key + "&random=" + random; - - String content = HttpUtil.httpPost(url, postContent); - - if (StrUtil.isBlank(content)) { - return false; - } - - JSONObject resultJson = JSON.parseObject(content); - Integer result = resultJson.getInteger("result"); - if (result != null && result == 0) { - return true; - } else { - LogKit.error("qcloud sms send error : " + content); - return false; - } - } - - - public static void main(String[] args) { - - String app_id = ""; - String app_key = ""; - - JPressOptions.set(JPressConsts.OPTION_CONNECTION_SMS_APPID, app_id); - JPressOptions.set(JPressConsts.OPTION_CONNECTION_SMS_APPSECRET, app_key); - - - SmsMessage sms = new SmsMessage(); - sms.setMobile("18611220000"); - sms.setTemplate("215659"); - sms.setSign("JPress大本营"); - sms.setCode("1234"); - - boolean sendOk = new QCloudSmsSender().send(sms); - - System.out.println(sendOk); - System.out.println("===============finished!==================="); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.sms; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jfinal.kit.HashKit; +import com.jfinal.kit.LogKit; +import io.jboot.utils.HttpUtil; +import io.jboot.utils.StrUtil; +import io.jpress.JPressConsts; +import io.jpress.JPressOptions; + +import java.util.Random; + +/** + * 腾讯云短信发送 + * api 接口文档 :https://cloud.tencent.com/document/product/382/5976 + */ +public class QCloudSmsSender implements SmsSender { + + private static final String SMS_JSON = "{\"ext\":\"\",\"extend\":\"\",\"params\":[\"{code}\",30],\"sig\":\"{sig}\",\"sign\":\"{sign}\",\"tel\":{\"mobile\":\"{mobile}\",\"nationcode\":\"86\"},\"time\":{time},\"tpl_id\":{tpl_id}}"; + private static final String SMS_NO_CODE_JSON = "{\"ext\":\"\",\"extend\":\"\",\"params\":[30],\"sig\":\"{sig}\",\"sign\":\"{sign}\",\"tel\":{\"mobile\":\"{mobile}\",\"nationcode\":\"86\"},\"time\":{time},\"tpl_id\":{tpl_id}}"; + + + @Override + public boolean send(SmsMessage sms) { + + String app_key = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_APPID); + String app_secret = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_APPSECRET); + + String random = new Random().nextInt(1000000) + ""; + String time = System.currentTimeMillis() / 1000 + ""; + + String srcStr = "appkey=" + app_secret + "&random=" + random + "&time=" + time + "&mobile=" + sms.getMobile(); + String sig = HashKit.sha256(srcStr); + + boolean hasCode = StrUtil.isNotBlank(sms.getCode()); + + String postContent = (hasCode ? SMS_JSON.replace("{code}", sms.getCode()) : SMS_NO_CODE_JSON) + .replace("{sig}", sig) + .replace("{sign}", sms.getSign()) + .replace("{mobile}", sms.getMobile()) + .replace("{time}", time) + .replace("{tpl_id}", sms.getTemplate()); + + String url = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms?sdkappid=" + app_key + "&random=" + random; + + String content = HttpUtil.httpPost(url, postContent); + + if (StrUtil.isBlank(content)) { + return false; + } + + JSONObject resultJson = JSON.parseObject(content); + Integer result = resultJson.getInteger("result"); + if (result != null && result == 0) { + return true; + } else { + LogKit.error("qcloud sms send error : " + content); + return false; + } + } + + + public static void main(String[] args) { + + String app_id = ""; + String app_key = ""; + + JPressOptions.set(JPressConsts.OPTION_CONNECTION_SMS_APPID, app_id); + JPressOptions.set(JPressConsts.OPTION_CONNECTION_SMS_APPSECRET, app_key); + + + SmsMessage sms = new SmsMessage(); + sms.setMobile("18611220000"); + sms.setTemplate("215659"); + sms.setSign("JPress大本营"); + sms.setCode("1234"); + + boolean sendOk = new QCloudSmsSender().send(sms); + + System.out.println(sendOk); + System.out.println("===============finished!==================="); + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/sms/SmsKit.java b/jpress-commons/src/main/java/io/jpress/commons/sms/SmsKit.java index 96175a5c107b637b3d970453729d4088539023f5..f3062532a5ce06b94090aec1c1de9d9383fb03f6 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/sms/SmsKit.java +++ b/jpress-commons/src/main/java/io/jpress/commons/sms/SmsKit.java @@ -1,92 +1,92 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.sms; - -import io.jboot.Jboot; -import io.jpress.commons.utils.CommonsUtils; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Package io.jpress.commons.sms - */ -public class SmsKit { - - private static final String CACHE_NAME = "sms_code"; - - /** - * 发送短信 - * - * @param mobile 手机号 - * @param template 短信模板 - * @param sign 短信签名 - * @return - */ - public static boolean sendSms(String mobile, String template, String sign) { - SmsMessage sms = new SmsMessage(); - sms.setSign(sign); - sms.setMobile(mobile); - sms.setTemplate(template); - return sms.send(); - } - - /** - * 发送短信验证码 - * - * @param mobile - * @param code - * @param template - * @param sign - * @return - */ - public static boolean sendCode(String mobile, String code, String template, String sign) { - - SmsMessage sms = new SmsMessage(); - sms.setCode(code); - sms.setSign(sign); - sms.setMobile(mobile); - sms.setTemplate(template); - - if (sms.send()) { - //有效期,2个小时 - Jboot.getCache().put(CACHE_NAME, mobile, code, 60 * 60 * 2); - return true; - } - return false; - } - - /** - * 验证用户输入的手机号是否正确 - * - * @param mobile - * @param code - * @return - */ - public static boolean validateCode(String mobile, String code) { - String cacheCode = Jboot.getCache().get(CACHE_NAME, mobile); - return cacheCode != null && cacheCode.equals(code); - } - - - /** - * 生成一个四位数字的码 - * - * @return - */ - public static String generateCode() { - return CommonsUtils.generateCode(); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.sms; + +import io.jboot.Jboot; +import io.jpress.commons.utils.CommonsUtils; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Package io.jpress.commons.sms + */ +public class SmsKit { + + private static final String CACHE_NAME = "sms_code"; + + /** + * 发送短信 + * + * @param mobile 手机号 + * @param template 短信模板 + * @param sign 短信签名 + * @return + */ + public static boolean sendSms(String mobile, String template, String sign) { + SmsMessage sms = new SmsMessage(); + sms.setSign(sign); + sms.setMobile(mobile); + sms.setTemplate(template); + return sms.send(); + } + + /** + * 发送短信验证码 + * + * @param mobile + * @param code + * @param template + * @param sign + * @return + */ + public static boolean sendCode(String mobile, String code, String template, String sign) { + + SmsMessage sms = new SmsMessage(); + sms.setCode(code); + sms.setSign(sign); + sms.setMobile(mobile); + sms.setTemplate(template); + + if (sms.send()) { + //有效期,2个小时 + Jboot.getCache().put(CACHE_NAME, mobile, code, 60 * 60 * 2); + return true; + } + return false; + } + + /** + * 验证用户输入的手机号是否正确 + * + * @param mobile + * @param code + * @return + */ + public static boolean validateCode(String mobile, String code) { + String cacheCode = Jboot.getCache().get(CACHE_NAME, mobile); + return cacheCode != null && cacheCode.equals(code); + } + + + /** + * 生成一个四位数字的码 + * + * @return + */ + public static String generateCode() { + return CommonsUtils.generateCode(); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/sms/SmsMessage.java b/jpress-commons/src/main/java/io/jpress/commons/sms/SmsMessage.java index 31bf9fb1a54d6742e0fcc4a169141802a26cae2c..339cfc6af558bcdc093baa207921850276aeecfc 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/sms/SmsMessage.java +++ b/jpress-commons/src/main/java/io/jpress/commons/sms/SmsMessage.java @@ -1,74 +1,74 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.sms; - -public class SmsMessage { - - private String mobile; - private String sign; //阿里云和腾讯云需要签名 - private String template; - private String code; //验证码 - - - public static SmsMessage create(String mobile, Object code, String template, String sign) { - SmsMessage sms = new SmsMessage(); - sms.setCode(code.toString()); - sms.setSign(sign); - sms.setMobile(mobile); - sms.setTemplate(template); - return sms; - } - - - public String getMobile() { - return mobile; - } - - public void setMobile(String mobile) { - this.mobile = mobile; - } - - public String getSign() { - return sign; - } - - public void setSign(String sign) { - this.sign = sign; - } - - public String getTemplate() { - return template; - } - - public void setTemplate(String template) { - this.template = template; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - /** - * 发送短信 - */ - public boolean send() { - return SmsSenderFactory.createSender().send(this); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.sms; + +public class SmsMessage { + + private String mobile; + private String sign; //阿里云和腾讯云需要签名 + private String template; + private String code; //验证码 + + + public static SmsMessage create(String mobile, Object code, String template, String sign) { + SmsMessage sms = new SmsMessage(); + sms.setCode(code.toString()); + sms.setSign(sign); + sms.setMobile(mobile); + sms.setTemplate(template); + return sms; + } + + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + /** + * 发送短信 + */ + public boolean send() { + return SmsSenderFactory.createSender().send(this); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/sms/SmsSender.java b/jpress-commons/src/main/java/io/jpress/commons/sms/SmsSender.java index 7c5fd608969c7707abe9899152da3f1442a606b8..932441df49185fe27103c99ff2b58a91079fc57b 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/sms/SmsSender.java +++ b/jpress-commons/src/main/java/io/jpress/commons/sms/SmsSender.java @@ -1,22 +1,22 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.sms; - -public interface SmsSender { - - public boolean send(SmsMessage sms); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.sms; + +public interface SmsSender { + + public boolean send(SmsMessage sms); + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/sms/SmsSenderFactory.java b/jpress-commons/src/main/java/io/jpress/commons/sms/SmsSenderFactory.java index bc0b1c788834e787baa42a69cb2b6c0cfb73ed69..bbc4b33fab9224eeff77dc7e42c361ced3617b15 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/sms/SmsSenderFactory.java +++ b/jpress-commons/src/main/java/io/jpress/commons/sms/SmsSenderFactory.java @@ -1,53 +1,53 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.sms; - - -import io.jboot.core.spi.JbootSpiLoader; -import io.jboot.utils.StrUtil; -import io.jpress.JPressConsts; -import io.jpress.JPressOptions; - -public class SmsSenderFactory { - - - public static SmsSender createSender() { - - boolean smsEnable = JPressOptions.getAsBool(JPressConsts.OPTION_CONNECTION_SMS_ENABLE); - - if (smsEnable == false) { - return new NonSmsSender(); - } - - String type = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_TYPE); - - // 默认使用阿里云 - if (StrUtil.isBlank(type)) { - return new AliyunSmsSender(); - } - - switch (type) { - case JPressConsts.SMS_TYPE_ALIYUN: - return new AliyunSmsSender(); - case JPressConsts.SMS_TYPE_QCLOUD: - return new QCloudSmsSender(); - } - - //其他通过SPI扩展机制加载 - return JbootSpiLoader.load(SmsSender.class, type); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.sms; + + +import io.jboot.core.spi.JbootSpiLoader; +import io.jboot.utils.StrUtil; +import io.jpress.JPressConsts; +import io.jpress.JPressOptions; + +public class SmsSenderFactory { + + + public static SmsSender createSender() { + + boolean smsEnable = JPressOptions.getAsBool(JPressConsts.OPTION_CONNECTION_SMS_ENABLE); + + if (smsEnable == false) { + return new NonSmsSender(); + } + + String type = JPressOptions.get(JPressConsts.OPTION_CONNECTION_SMS_TYPE); + + // 默认使用阿里云 + if (StrUtil.isBlank(type)) { + return new AliyunSmsSender(); + } + + switch (type) { + case JPressConsts.SMS_TYPE_ALIYUN: + return new AliyunSmsSender(); + case JPressConsts.SMS_TYPE_QCLOUD: + return new QCloudSmsSender(); + } + + //其他通过SPI扩展机制加载 + return JbootSpiLoader.load(SmsSender.class, type); + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/AliyunOssUtils.java b/jpress-commons/src/main/java/io/jpress/commons/utils/AliyunOssUtils.java index a604bc99f093e9f86dc65846c0cc9a129d5b14ca..192f7691fa6e76adb662883676996a4a28b99653 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/AliyunOssUtils.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/AliyunOssUtils.java @@ -1,169 +1,169 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import com.aliyun.oss.OSSClient; -import com.aliyun.oss.common.auth.DefaultCredentialProvider; -import com.aliyun.oss.model.GetObjectRequest; -import com.jfinal.kit.LogKit; -import com.jfinal.log.Log; -import io.jboot.utils.NamedThreadPools; -import io.jboot.utils.StrUtil; -import io.jpress.JPressOptions; - -import java.io.File; -import java.util.concurrent.ExecutorService; - - -public class AliyunOssUtils { - - static Log log = Log.getLog(AliyunOssUtils.class); - - - private static final String KEY_ENABLE = "attachment_aliyunoss_enable"; - private static final String KEY_ENDPOINT = "attachment_aliyunoss_endpoint"; - private static final String KEY_ACCESSKEYID = "attachment_aliyunoss_accesskeyid"; - private static final String KEY_ACCESSKEYSECRET = "attachment_aliyunoss_accesskeysecret"; - private static final String KEY_BUCKETNAME = "attachment_aliyunoss_bucketname"; - private static final String KEY_OSS_DEL = "attachment_aliyunoss_del"; - - - private static ExecutorService fixedThreadPool = NamedThreadPools.newFixedThreadPool(3,"aliyun-oss-upload"); - - /** - * 同步本地文件到阿里云OSS - * - * @param path - * @param file - * @return - */ - public static void upload(String path, File file) { - fixedThreadPool.execute(() -> { - uploadsync(path, file); - }); - } - - /** - * 同步本地文件到阿里云OSS - * - * @param path - * @param file - * @return - */ - public static boolean uploadsync(String path, File file) { - - boolean enable = JPressOptions.getAsBool(KEY_ENABLE); - - if (!enable || StrUtil.isBlank(path)) { - return false; - } - - path = removeFileSeparator(path); - path = path.replace('\\', '/'); - - String ossBucketName = JPressOptions.get(KEY_BUCKETNAME); - OSSClient ossClient = createOSSClient(); - - try { - ossClient.putObject(ossBucketName, path, file); - boolean success = ossClient.doesObjectExist(ossBucketName, path); - if (!success) { - LogKit.error("aliyun oss upload error! path:" + path + "\nfile:" + file); - } - return success; - - } catch (Throwable e) { - log.error("aliyun oss upload error!!!", e); - return false; - } finally { - ossClient.shutdown(); - } - } - - /** - * 如果文件以 / 或者 \ 开头,去除 / 或 \ 符号 - */ - private static String removeFileSeparator(String path) { - while (path.startsWith("/") || path.startsWith("\\")) { - path = path.substring(1, path.length()); - } - return path; - } - - /** - * 同步 阿里云OSS 到本地 - * - * @param path - * @param toFile - * @return - */ - public static boolean download(String path, File toFile) { - boolean enable = JPressOptions.getAsBool(KEY_ENABLE); - - if (!enable || StrUtil.isBlank(path)) { - return false; - } - - path = removeFileSeparator(path); - String ossBucketName = JPressOptions.get(KEY_BUCKETNAME); - OSSClient ossClient = createOSSClient(); - try { - - if (!toFile.getParentFile().exists()) { - toFile.getParentFile().mkdirs(); - } - - if (!toFile.exists()) { - toFile.createNewFile(); - } - ossClient.getObject(new GetObjectRequest(ossBucketName, path), toFile); - return true; - } catch (Throwable e) { - log.error("aliyun oss download error!!! path:" + path + " toFile:" + toFile, e); - if (toFile.exists()) { - toFile.delete(); - } - return false; - } finally { - ossClient.shutdown(); - } - } - - private static OSSClient createOSSClient() { - String endpoint = JPressOptions.get(KEY_ENDPOINT); - String accessId = JPressOptions.get(KEY_ACCESSKEYID); - String accessKey = JPressOptions.get(KEY_ACCESSKEYSECRET); - return new OSSClient(endpoint, new DefaultCredentialProvider(accessId, accessKey), null); - } - /** - * 删除一个OSS中的文件 - * @param objectName - */ - public static void delete(String objectName){ - boolean ossDelEnable = JPressOptions.getAsBool(KEY_OSS_DEL); - if (ossDelEnable){ - OSSClient ossClient = createOSSClient(); - try { - ossClient.deleteObject(JPressOptions.get(KEY_BUCKETNAME), objectName); - }catch (Exception e){ - - }finally { - ossClient.shutdown(); - } - } - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.common.auth.DefaultCredentialProvider; +import com.aliyun.oss.model.GetObjectRequest; +import com.jfinal.kit.LogKit; +import com.jfinal.log.Log; +import io.jboot.utils.NamedThreadPools; +import io.jboot.utils.StrUtil; +import io.jpress.JPressOptions; + +import java.io.File; +import java.util.concurrent.ExecutorService; + + +public class AliyunOssUtils { + + static Log log = Log.getLog(AliyunOssUtils.class); + + + private static final String KEY_ENABLE = "attachment_aliyunoss_enable"; + private static final String KEY_ENDPOINT = "attachment_aliyunoss_endpoint"; + private static final String KEY_ACCESSKEYID = "attachment_aliyunoss_accesskeyid"; + private static final String KEY_ACCESSKEYSECRET = "attachment_aliyunoss_accesskeysecret"; + private static final String KEY_BUCKETNAME = "attachment_aliyunoss_bucketname"; + private static final String KEY_OSS_DEL = "attachment_aliyunoss_del"; + + + private static ExecutorService fixedThreadPool = NamedThreadPools.newFixedThreadPool(3,"aliyun-oss-upload"); + + /** + * 同步本地文件到阿里云OSS + * + * @param path + * @param file + * @return + */ + public static void upload(String path, File file) { + fixedThreadPool.execute(() -> { + uploadsync(path, file); + }); + } + + /** + * 同步本地文件到阿里云OSS + * + * @param path + * @param file + * @return + */ + public static boolean uploadsync(String path, File file) { + + boolean enable = JPressOptions.getAsBool(KEY_ENABLE); + + if (!enable || StrUtil.isBlank(path)) { + return false; + } + + path = removeFileSeparator(path); + path = path.replace('\\', '/'); + + String ossBucketName = JPressOptions.get(KEY_BUCKETNAME); + OSSClient ossClient = createOSSClient(); + + try { + ossClient.putObject(ossBucketName, path, file); + boolean success = ossClient.doesObjectExist(ossBucketName, path); + if (!success) { + LogKit.error("aliyun oss upload error! path:" + path + "\nfile:" + file); + } + return success; + + } catch (Throwable e) { + log.error("aliyun oss upload error!!!", e); + return false; + } finally { + ossClient.shutdown(); + } + } + + /** + * 如果文件以 / 或者 \ 开头,去除 / 或 \ 符号 + */ + private static String removeFileSeparator(String path) { + while (path.startsWith("/") || path.startsWith("\\")) { + path = path.substring(1, path.length()); + } + return path; + } + + /** + * 同步 阿里云OSS 到本地 + * + * @param path + * @param toFile + * @return + */ + public static boolean download(String path, File toFile) { + boolean enable = JPressOptions.getAsBool(KEY_ENABLE); + + if (!enable || StrUtil.isBlank(path)) { + return false; + } + + path = removeFileSeparator(path); + String ossBucketName = JPressOptions.get(KEY_BUCKETNAME); + OSSClient ossClient = createOSSClient(); + try { + + if (!toFile.getParentFile().exists()) { + toFile.getParentFile().mkdirs(); + } + + if (!toFile.exists()) { + toFile.createNewFile(); + } + ossClient.getObject(new GetObjectRequest(ossBucketName, path), toFile); + return true; + } catch (Throwable e) { + log.error("aliyun oss download error!!! path:" + path + " toFile:" + toFile, e); + if (toFile.exists()) { + toFile.delete(); + } + return false; + } finally { + ossClient.shutdown(); + } + } + + private static OSSClient createOSSClient() { + String endpoint = JPressOptions.get(KEY_ENDPOINT); + String accessId = JPressOptions.get(KEY_ACCESSKEYID); + String accessKey = JPressOptions.get(KEY_ACCESSKEYSECRET); + return new OSSClient(endpoint, new DefaultCredentialProvider(accessId, accessKey), null); + } + /** + * 删除一个OSS中的文件 + * @param objectName + */ + public static void delete(String objectName){ + boolean ossDelEnable = JPressOptions.getAsBool(KEY_OSS_DEL); + if (ossDelEnable){ + OSSClient ossClient = createOSSClient(); + try { + ossClient.deleteObject(JPressOptions.get(KEY_BUCKETNAME), objectName); + }catch (Exception e){ + + }finally { + ossClient.shutdown(); + } + } + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/AttachmentUtils.java b/jpress-commons/src/main/java/io/jpress/commons/utils/AttachmentUtils.java index 31c9a68617e244fe5c26304aae90d46b5ccd94af..ee6804b04461509c6efc24e84c65f4a1a60ac595 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/AttachmentUtils.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/AttachmentUtils.java @@ -1,142 +1,142 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import com.jfinal.log.Log; -import com.jfinal.upload.UploadFile; -import io.jboot.utils.FileUtil; -import io.jboot.utils.StrUtil; -import io.jpress.JPressConfig; - -import java.io.File; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; - -public class AttachmentUtils { - - private static final Log LOG = Log.getLog(AttachmentUtils.class); - - /** - * @param uploadFile - * @return new file relative path - */ - public static String moveFile(UploadFile uploadFile) { - if (uploadFile == null) { - return null; - } - - File file = uploadFile.getFile(); - if (!file.exists()) { - return null; - } - - File newfile = newAttachemnetFile(FileUtil.getSuffix(file.getName())); - - if (!newfile.getParentFile().exists()) { - newfile.getParentFile().mkdirs(); - } - - try { - org.apache.commons.io.FileUtils.moveFile(file, newfile); - newfile.setReadable(true,false); - } catch (IOException e) { - LOG.error(e.toString(), e); - } - - String attachmentRoot = JPressConfig.me.getAttachmentRootOrWebRoot(); - return FileUtil.removePrefix(newfile.getAbsolutePath(), attachmentRoot); - } - - public static File newAttachemnetFile(String suffix) { - - String attachmentRoot = JPressConfig.me.getAttachmentRootOrWebRoot(); - - String uuid = UUID.randomUUID().toString().replace("-", ""); - - StringBuilder newFileName = new StringBuilder(attachmentRoot) - .append(File.separator).append("attachment") - .append(File.separator).append(new SimpleDateFormat("yyyyMMdd").format(new Date())) - .append(File.separator).append(uuid) - .append(suffix); - - return new File(newFileName.toString()); - } - - public static File file(String path) { - String attachmentRoot = JPressConfig.me.getAttachmentRootOrWebRoot(); - return new File(attachmentRoot, path); - } - - public static String getAttachmentPath(String path) { - String attachmentRoot = JPressConfig.me.getAttachmentRootOrWebRoot(); - return path != null && path.startsWith(attachmentRoot) - ? path.substring(attachmentRoot.length()) - : path; - } - - static List imageSuffix = new ArrayList<>(); - - static { - imageSuffix.add(".jpg"); - imageSuffix.add(".jpeg"); - imageSuffix.add(".png"); - imageSuffix.add(".bmp"); - imageSuffix.add(".gif"); - imageSuffix.add(".webp"); - } - - public static boolean isImage(String path) { - String sufffix = FileUtil.getSuffix(path); - if (StrUtil.isNotBlank(sufffix)) { - return imageSuffix.contains(sufffix.toLowerCase()); - } - return false; - } - - static List unSafeFilesSuffix = new ArrayList<>(); - - static { - unSafeFilesSuffix.add(".jsp"); - unSafeFilesSuffix.add(".jspx"); - unSafeFilesSuffix.add(".php"); - unSafeFilesSuffix.add(".html"); - unSafeFilesSuffix.add(".htm"); - unSafeFilesSuffix.add(".css"); - unSafeFilesSuffix.add(".js"); - unSafeFilesSuffix.add(".exe"); - unSafeFilesSuffix.add(".sh"); - unSafeFilesSuffix.add(".bat"); - unSafeFilesSuffix.add(".jar"); - unSafeFilesSuffix.add(".war"); - } - - public static boolean isUnSafe(File file) { - String sufffix = FileUtil.getSuffix(file.getName()); - if (StrUtil.isNotBlank(sufffix)) { - return unSafeFilesSuffix.contains(sufffix.toLowerCase()); - } - return false; - } - - public static void main(String[] args) { - System.out.println(FileUtil.getSuffix("xxx.jpg")); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import com.jfinal.log.Log; +import com.jfinal.upload.UploadFile; +import io.jboot.utils.FileUtil; +import io.jboot.utils.StrUtil; +import io.jpress.JPressConfig; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +public class AttachmentUtils { + + private static final Log LOG = Log.getLog(AttachmentUtils.class); + + /** + * @param uploadFile + * @return new file relative path + */ + public static String moveFile(UploadFile uploadFile) { + if (uploadFile == null) { + return null; + } + + File file = uploadFile.getFile(); + if (!file.exists()) { + return null; + } + + File newfile = newAttachemnetFile(FileUtil.getSuffix(file.getName())); + + if (!newfile.getParentFile().exists()) { + newfile.getParentFile().mkdirs(); + } + + try { + org.apache.commons.io.FileUtils.moveFile(file, newfile); + newfile.setReadable(true,false); + } catch (IOException e) { + LOG.error(e.toString(), e); + } + + String attachmentRoot = JPressConfig.me.getAttachmentRootOrWebRoot(); + return FileUtil.removePrefix(newfile.getAbsolutePath(), attachmentRoot); + } + + public static File newAttachemnetFile(String suffix) { + + String attachmentRoot = JPressConfig.me.getAttachmentRootOrWebRoot(); + + String uuid = UUID.randomUUID().toString().replace("-", ""); + + StringBuilder newFileName = new StringBuilder(attachmentRoot) + .append(File.separator).append("attachment") + .append(File.separator).append(new SimpleDateFormat("yyyyMMdd").format(new Date())) + .append(File.separator).append(uuid) + .append(suffix); + + return new File(newFileName.toString()); + } + + public static File file(String path) { + String attachmentRoot = JPressConfig.me.getAttachmentRootOrWebRoot(); + return new File(attachmentRoot, path); + } + + public static String getAttachmentPath(String path) { + String attachmentRoot = JPressConfig.me.getAttachmentRootOrWebRoot(); + return path != null && path.startsWith(attachmentRoot) + ? path.substring(attachmentRoot.length()) + : path; + } + + static List imageSuffix = new ArrayList<>(); + + static { + imageSuffix.add(".jpg"); + imageSuffix.add(".jpeg"); + imageSuffix.add(".png"); + imageSuffix.add(".bmp"); + imageSuffix.add(".gif"); + imageSuffix.add(".webp"); + } + + public static boolean isImage(String path) { + String sufffix = FileUtil.getSuffix(path); + if (StrUtil.isNotBlank(sufffix)) { + return imageSuffix.contains(sufffix.toLowerCase()); + } + return false; + } + + static List unSafeFilesSuffix = new ArrayList<>(); + + static { + unSafeFilesSuffix.add(".jsp"); + unSafeFilesSuffix.add(".jspx"); + unSafeFilesSuffix.add(".php"); + unSafeFilesSuffix.add(".html"); + unSafeFilesSuffix.add(".htm"); + unSafeFilesSuffix.add(".css"); + unSafeFilesSuffix.add(".js"); + unSafeFilesSuffix.add(".exe"); + unSafeFilesSuffix.add(".sh"); + unSafeFilesSuffix.add(".bat"); + unSafeFilesSuffix.add(".jar"); + unSafeFilesSuffix.add(".war"); + } + + public static boolean isUnSafe(File file) { + String sufffix = FileUtil.getSuffix(file.getName()); + if (StrUtil.isNotBlank(sufffix)) { + return unSafeFilesSuffix.contains(sufffix.toLowerCase()); + } + return false; + } + + public static void main(String[] args) { + System.out.println(FileUtil.getSuffix("xxx.jpg")); + } + +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/CommonsUtils.java b/jpress-commons/src/main/java/io/jpress/commons/utils/CommonsUtils.java index 60215fd55ba2f81a5b50686519e4fd5ec79275f4..c3dbf86bfe89d361bdb7d9a749aff661f99bae80 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/CommonsUtils.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/CommonsUtils.java @@ -1,134 +1,134 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import com.jfinal.plugin.activerecord.Model; -import io.jboot.utils.StrUtil; -import org.apache.commons.lang3.ArrayUtils; - -import java.util.Map; -import java.util.Random; -import java.util.Set; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Package io.jpress.commons.utils - */ -public class CommonsUtils { - - - public static String generateCode() { - Random random = new Random(); - return String.valueOf(random.nextInt(9999 - 1000 + 1) + 1000); - } - - public static void quietlyClose(AutoCloseable... autoCloseables) { - for (AutoCloseable closeable : autoCloseables) { - if (closeable != null) { - try { - closeable.close(); - } catch (Exception e) { - // do nothing - } - } - } - } - - - public static String maxLength(String content, int maxLength) { - return maxLength(content, maxLength, null); - } - - - public static String maxLength(String content, int maxLength, String suffix) { - if (StrUtil.isBlank(content)) { - return content; - } - - if (maxLength <= 0) { - throw new IllegalArgumentException("maxLength 必须大于 0 "); - } - - if (StrUtil.isNotBlank(suffix)) { - return content.length() <= maxLength - ? content : - content.substring(0, maxLength) + suffix; - - } else { - return content.length() <= maxLength - ? content : - content.substring(0, maxLength); - - } - } - - public static String removeSuffix(String url) { - - int indexOf = url.indexOf("."); - - if (indexOf == -1) { - return url; - } - - return url.substring(0, indexOf); - } - - /** - * 防止 model 存储关于 xss 相关代码 - * - * @param model - */ - public static void escapeModel(Model model, String... ignoreAttrs) { - String[] attrNames = model._getAttrNames(); - for (String attr : attrNames) { - - if (ArrayUtils.contains(ignoreAttrs, attr)) { - continue; - } - - Object value = model.get(attr); - - if (value != null && value instanceof String) { - model.set(attr, StrUtil.escapeHtml(value.toString())); - } - } - } - - public static void escapeMap(Map map, Object... ignoreKeys) { - if (map == null || map.isEmpty()) { - return; - } - - Set keys = map.keySet(); - for (Object key : keys) { - if (ArrayUtils.contains(ignoreKeys, key)) { - continue; - } - - Object value = map.get(key); - - if (value != null && value instanceof String) { - map.put(key, StrUtil.escapeHtml(value.toString())); - } - } - } - - - public static void main(String[] args) { - System.out.println(generateCode()); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import com.jfinal.plugin.activerecord.Model; +import io.jboot.utils.StrUtil; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.Map; +import java.util.Random; +import java.util.Set; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Package io.jpress.commons.utils + */ +public class CommonsUtils { + + + public static String generateCode() { + Random random = new Random(); + return String.valueOf(random.nextInt(9999 - 1000 + 1) + 1000); + } + + public static void quietlyClose(AutoCloseable... autoCloseables) { + for (AutoCloseable closeable : autoCloseables) { + if (closeable != null) { + try { + closeable.close(); + } catch (Exception e) { + // do nothing + } + } + } + } + + + public static String maxLength(String content, int maxLength) { + return maxLength(content, maxLength, null); + } + + + public static String maxLength(String content, int maxLength, String suffix) { + if (StrUtil.isBlank(content)) { + return content; + } + + if (maxLength <= 0) { + throw new IllegalArgumentException("maxLength 必须大于 0 "); + } + + if (StrUtil.isNotBlank(suffix)) { + return content.length() <= maxLength + ? content : + content.substring(0, maxLength) + suffix; + + } else { + return content.length() <= maxLength + ? content : + content.substring(0, maxLength); + + } + } + + public static String removeSuffix(String url) { + + int indexOf = url.indexOf("."); + + if (indexOf == -1) { + return url; + } + + return url.substring(0, indexOf); + } + + /** + * 防止 model 存储关于 xss 相关代码 + * + * @param model + */ + public static void escapeModel(Model model, String... ignoreAttrs) { + String[] attrNames = model._getAttrNames(); + for (String attr : attrNames) { + + if (ArrayUtils.contains(ignoreAttrs, attr)) { + continue; + } + + Object value = model.get(attr); + + if (value != null && value instanceof String) { + model.set(attr, StrUtil.escapeHtml(value.toString())); + } + } + } + + public static void escapeMap(Map map, Object... ignoreKeys) { + if (map == null || map.isEmpty()) { + return; + } + + Set keys = map.keySet(); + for (Object key : keys) { + if (ArrayUtils.contains(ignoreKeys, key)) { + continue; + } + + Object value = map.get(key); + + if (value != null && value instanceof String) { + map.put(key, StrUtil.escapeHtml(value.toString())); + } + } + } + + + public static void main(String[] args) { + System.out.println(generateCode()); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/ImageUtils.java b/jpress-commons/src/main/java/io/jpress/commons/utils/ImageUtils.java index 2fc22f2a0f1a4c368dbbf65d321009e7346dca36..f01ffa2a105c6fb07d5dfc27fb59d79be989fadd 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/ImageUtils.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/ImageUtils.java @@ -1,353 +1,353 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import com.jfinal.kit.StrKit; -import com.jfinal.log.Log; -import org.apache.commons.io.FileUtils; - -import javax.imageio.ImageIO; -import javax.imageio.ImageReadParam; -import javax.imageio.ImageReader; -import javax.imageio.stream.ImageInputStream; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Iterator; - -public class ImageUtils { - private static final Log log = Log.getLog(ImageUtils.class); - - private final static String[] imgExts = new String[]{"jpg", "jpeg", "png", "bmp"}; - - public static String getExtName(String fileName) { - int index = fileName.lastIndexOf('.'); - if (index != -1 && (index + 1) < fileName.length()) { - return fileName.substring(index + 1); - } else { - return null; - } - } - - - /** - * 过文件扩展名,判断是否为支持的图像文件 - * - * @param fileName - * @return 是图片则返回 true,否则返回 false - */ - public static boolean isImageExtName(String fileName) { - if (StrKit.isBlank(fileName)) { - return false; - } - fileName = fileName.trim().toLowerCase(); - String ext = getExtName(fileName); - if (ext != null) { - for (String s : imgExts) { - if (s.equals(ext)) { - return true; - } - } - } - return false; - } - - public static final boolean notImageExtName(String fileName) { - return !isImageExtName(fileName); - } - - public static int[] ratio(String src) throws IOException { - BufferedImage bufferedImage = ImageIO.read(new File(src)); - int width = bufferedImage.getWidth(); - int height = bufferedImage.getHeight(); - return new int[]{width, height}; - } - - public static String ratioAsString(String src) throws IOException { - File file = new File(src); - if (!file.exists()) { - return null; - } - BufferedImage bufferedImage = ImageIO.read(file); - int width = bufferedImage.getWidth(); - int height = bufferedImage.getHeight(); - return String.format("%s x %s", width, height); - } - - /** - * 等比缩放,居中剪切,自动在在当前目录下生产新图 - * 例如:aaa.jpg 宽高为100和200,自动在当前目录下生成新图 aaa_100x200.jpg 的图 - * - * @param src - * @param w - * @param h - * @return 放回新图的路径 - * @throws IOException - */ - public static String scale(String src, int w, int h) throws IOException { - int inserTo = src.lastIndexOf("."); - String dest = src.substring(0, inserTo) + String.format("_%sx%s", w, h) + src.substring(inserTo); - scale(src, dest, w, h); - return dest; - } - - /** - * 等比缩放,居中剪切 - * - * @param src - * @param dest - * @param w - * @param h - * @throws IOException - */ - public static void scale(String src, String dest, int w, int h) throws IOException { - - if (notImageExtName(src)) { - throw new IllegalArgumentException("只支持如下几种图片格式:jpg、jpeg、png、bmp"); - } - - Iterator iterator = ImageIO.getImageReadersByFormatName(getExtName(src)); - ImageReader reader = (ImageReader) iterator.next(); - - InputStream in = new FileInputStream(src); - ImageInputStream iis = ImageIO.createImageInputStream(in); - reader.setInput(iis); - - BufferedImage srcBuffered = readBuffereImage(reader, w, h); - BufferedImage targetBuffered = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); - - Graphics graphics = targetBuffered.getGraphics(); - graphics.drawImage(srcBuffered.getScaledInstance(w, h, Image.SCALE_DEFAULT), 0, 0, null); // 绘制缩小后的图 - - graphics.dispose(); - srcBuffered.flush(); - save(targetBuffered, dest); - targetBuffered.flush(); - } - - private static BufferedImage readBuffereImage(ImageReader reader, int w, int h) throws IOException { - ImageReadParam param = reader.getDefaultReadParam(); - int srcWidth = reader.getWidth(0); - int srcHeight = reader.getHeight(0); - - Rectangle rect = null; - - if ((float) w / h > (float) srcWidth / srcHeight) { - h = h * srcWidth / w; - w = srcWidth; - rect = new Rectangle(0, (srcHeight - h) / 2, w, h); - } else { - w = w * srcHeight / h; - h = srcHeight; - rect = new Rectangle((srcWidth - w) / 2, 0, w, h); - } - param.setSourceRegion(rect); - BufferedImage srcBuffered = reader.read(0, param); - return srcBuffered; - } - - public final static void pressImage(String watermarkImg, String srcImageFile) { - pressImage(watermarkImg, srcImageFile, srcImageFile, 5, -1, -1, 0.2f, 1); - } - - public final static void pressImage(String watermarkImg, String srcImageFile, String destImageFile) { - pressImage(watermarkImg, srcImageFile, destImageFile, 5, -1, -1, 0.2f, 1); - } - - public final static void pressImage(String watermarkImg, String srcImageFile, String destImageFile, int position, - float alpha) { - pressImage(watermarkImg, srcImageFile, destImageFile, position, -1, -1, 0.2f, alpha); - } - - /** - * @param watermarkImg 水印图片位置 - * @param srcImageFile 源图片位置 - * @param destImageFile 生成的图片位置 - * @param position 水印打印的位置: 1->左上角,2->右上角,3->居中,4->左下角,5->右下角 - * @param xOffset x轴偏移量,xOffset小于0,自动偏移 - * @param yOffset y轴偏移量,yOffset小于0,自动偏移 - * @param radio 默认为原图的 1/4 - * @param alpha 透明度(0~1),PNG图片建议设置为1 - */ - public final static void pressImage(String watermarkImg, String srcImageFile, String destImageFile, int position, - int xOffset, int yOffset, float radio, float alpha) { - - if (notImageExtName(srcImageFile)) { - throw new IllegalArgumentException("只支持如下几种图片格式:jpg、jpeg、png、bmp"); - } - - try { - File img = new File(srcImageFile); - Image src = ImageIO.read(img); - int srcWidth = src.getWidth(null); - int srcHeight = src.getHeight(null); - - BufferedImage image = new BufferedImage(srcWidth, srcHeight, BufferedImage.TYPE_INT_RGB); - Graphics2D graphics = image.createGraphics(); - graphics.drawImage(src, 0, 0, srcWidth, srcHeight, null); - - // 水印文件 - Image wmImage = ImageIO.read(new File(watermarkImg)); - int wmWidth = wmImage.getWidth(null); - int wmHeight = wmImage.getHeight(null); - - radio = radio <= 0 ? 0.2f : radio; - int newWidth = (int) (srcWidth * radio); - int newHeight = (int) (wmHeight * (newWidth / (float) wmWidth)); - - xOffset = (xOffset < 0) ? (int) (newWidth * 0.1f) : xOffset; - yOffset = (yOffset < 0) ? (int) (newHeight * 0.1f) : yOffset; - - int xPostion = 0; - int yPostion = 0; - - switch (position) { - case 1: - xPostion = xOffset; - yPostion = yOffset; - break; - case 2: - xPostion = (int) (srcWidth * (1 - radio) - xOffset); - yPostion = yOffset; - break; - case 3: - xPostion = (int) (srcWidth - newWidth) / 2; - yPostion = (int) (srcHeight - newHeight) / 2; - break; - case 4: - xPostion = xOffset; - yPostion = (int) (srcHeight - newHeight - yOffset); - break; - case 5: - xPostion = (int) (srcWidth * (1 - radio) - xOffset); - yPostion = (int) (srcHeight - newHeight - yOffset); - break; - default: - xPostion = xOffset; - yPostion = yOffset; - break; - } - - graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); - graphics.drawImage(wmImage, xPostion, yPostion, newWidth, newHeight, null); - // 水印文件结束 - graphics.dispose(); - - save(image, destImageFile); - - } catch (Exception e) { - log.warn("ImageUtils pressImage error", e); - } - } - - public static void zoom(int maxWidth, String srcImageFile, String destImageFile) { - try { - BufferedImage srcImage = ImageIO.read(new File(srcImageFile)); - int srcWidth = srcImage.getWidth(); - int srcHeight = srcImage.getHeight(); - - // 当宽度在 maxWidth 范围之内,直接copy - if (srcWidth <= maxWidth) { - FileUtils.copyFile(new File(srcImageFile), new File(destImageFile)); - } - // 当宽度超出 maxWidth 范围,将宽度变为 maxWidth,高度按比例缩放 - else { - float scalingRatio = (float) maxWidth / (float) srcWidth; // 计算缩放比率 - float maxHeight = ((float) srcHeight * scalingRatio); // 计算缩放后的高度 - BufferedImage ret = resize(srcImage, maxWidth, (int) maxHeight); - save(ret, destImageFile); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - - /** - * 剪切 - * - * @param srcImageFile 原图 - * @param destImageFile 存放的目标位置 - * @param left 起始点:左 - * @param top 起始点:上 - * @param width 宽 - * @param height 高 - */ - public static void crop(String srcImageFile, String destImageFile, int left, int top, int width, int height) { - - if (notImageExtName(srcImageFile)) { - throw new IllegalArgumentException("只支持如下几种图片格式:jpg、jpeg、png、bmp"); - } - - try { - BufferedImage bi = ImageIO.read(new File(srcImageFile)); - width = Math.min(width, bi.getWidth()); - height = Math.min(height, bi.getHeight()); - if (width <= 0) { - width = bi.getWidth(); - } - if (height <= 0) { - height = bi.getHeight(); - } - - left = Math.min(Math.max(0, left), bi.getWidth() - width); - top = Math.min(Math.max(0, top), bi.getHeight() - height); - - BufferedImage subimage = bi.getSubimage(left, top, width, height); - BufferedImage resizeImage = resize(subimage, 200, 200); - - save(resizeImage, destImageFile); - - } catch (Exception e) { - log.error(e.toString(), e); - } - } - - - /** - * 高保真缩放 - */ - private static BufferedImage resize(BufferedImage bi, int toWidth, int toHeight) { - Graphics g = null; - try { - Image scaledImage = bi.getScaledInstance(toWidth, toHeight, Image.SCALE_SMOOTH); - BufferedImage ret = new BufferedImage(toWidth, toHeight, BufferedImage.TYPE_INT_RGB); - g = ret.getGraphics(); - g.drawImage(scaledImage, 0, 0, null); - return ret; - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - if (g != null) { - g.dispose(); - } - } - } - - - private static void save(BufferedImage bi, String outputImageFile) { - try { - ImageIO.write(bi, getExtName(outputImageFile), new File(outputImageFile)); - } catch (Exception e) { - log.error(e.toString(), e); - } - } - - +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import com.jfinal.kit.StrKit; +import com.jfinal.log.Log; +import org.apache.commons.io.FileUtils; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; + +public class ImageUtils { + private static final Log log = Log.getLog(ImageUtils.class); + + private final static String[] imgExts = new String[]{"jpg", "jpeg", "png", "bmp"}; + + public static String getExtName(String fileName) { + int index = fileName.lastIndexOf('.'); + if (index != -1 && (index + 1) < fileName.length()) { + return fileName.substring(index + 1); + } else { + return null; + } + } + + + /** + * 过文件扩展名,判断是否为支持的图像文件 + * + * @param fileName + * @return 是图片则返回 true,否则返回 false + */ + public static boolean isImageExtName(String fileName) { + if (StrKit.isBlank(fileName)) { + return false; + } + fileName = fileName.trim().toLowerCase(); + String ext = getExtName(fileName); + if (ext != null) { + for (String s : imgExts) { + if (s.equals(ext)) { + return true; + } + } + } + return false; + } + + public static final boolean notImageExtName(String fileName) { + return !isImageExtName(fileName); + } + + public static int[] ratio(String src) throws IOException { + BufferedImage bufferedImage = ImageIO.read(new File(src)); + int width = bufferedImage.getWidth(); + int height = bufferedImage.getHeight(); + return new int[]{width, height}; + } + + public static String ratioAsString(String src) throws IOException { + File file = new File(src); + if (!file.exists()) { + return null; + } + BufferedImage bufferedImage = ImageIO.read(file); + int width = bufferedImage.getWidth(); + int height = bufferedImage.getHeight(); + return String.format("%s x %s", width, height); + } + + /** + * 等比缩放,居中剪切,自动在在当前目录下生产新图 + * 例如:aaa.jpg 宽高为100和200,自动在当前目录下生成新图 aaa_100x200.jpg 的图 + * + * @param src + * @param w + * @param h + * @return 放回新图的路径 + * @throws IOException + */ + public static String scale(String src, int w, int h) throws IOException { + int inserTo = src.lastIndexOf("."); + String dest = src.substring(0, inserTo) + String.format("_%sx%s", w, h) + src.substring(inserTo); + scale(src, dest, w, h); + return dest; + } + + /** + * 等比缩放,居中剪切 + * + * @param src + * @param dest + * @param w + * @param h + * @throws IOException + */ + public static void scale(String src, String dest, int w, int h) throws IOException { + + if (notImageExtName(src)) { + throw new IllegalArgumentException("只支持如下几种图片格式:jpg、jpeg、png、bmp"); + } + + Iterator iterator = ImageIO.getImageReadersByFormatName(getExtName(src)); + ImageReader reader = (ImageReader) iterator.next(); + + InputStream in = new FileInputStream(src); + ImageInputStream iis = ImageIO.createImageInputStream(in); + reader.setInput(iis); + + BufferedImage srcBuffered = readBuffereImage(reader, w, h); + BufferedImage targetBuffered = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + + Graphics graphics = targetBuffered.getGraphics(); + graphics.drawImage(srcBuffered.getScaledInstance(w, h, Image.SCALE_DEFAULT), 0, 0, null); // 绘制缩小后的图 + + graphics.dispose(); + srcBuffered.flush(); + save(targetBuffered, dest); + targetBuffered.flush(); + } + + private static BufferedImage readBuffereImage(ImageReader reader, int w, int h) throws IOException { + ImageReadParam param = reader.getDefaultReadParam(); + int srcWidth = reader.getWidth(0); + int srcHeight = reader.getHeight(0); + + Rectangle rect = null; + + if ((float) w / h > (float) srcWidth / srcHeight) { + h = h * srcWidth / w; + w = srcWidth; + rect = new Rectangle(0, (srcHeight - h) / 2, w, h); + } else { + w = w * srcHeight / h; + h = srcHeight; + rect = new Rectangle((srcWidth - w) / 2, 0, w, h); + } + param.setSourceRegion(rect); + BufferedImage srcBuffered = reader.read(0, param); + return srcBuffered; + } + + public final static void pressImage(String watermarkImg, String srcImageFile) { + pressImage(watermarkImg, srcImageFile, srcImageFile, 5, -1, -1, 0.2f, 1); + } + + public final static void pressImage(String watermarkImg, String srcImageFile, String destImageFile) { + pressImage(watermarkImg, srcImageFile, destImageFile, 5, -1, -1, 0.2f, 1); + } + + public final static void pressImage(String watermarkImg, String srcImageFile, String destImageFile, int position, + float alpha) { + pressImage(watermarkImg, srcImageFile, destImageFile, position, -1, -1, 0.2f, alpha); + } + + /** + * @param watermarkImg 水印图片位置 + * @param srcImageFile 源图片位置 + * @param destImageFile 生成的图片位置 + * @param position 水印打印的位置: 1->左上角,2->右上角,3->居中,4->左下角,5->右下角 + * @param xOffset x轴偏移量,xOffset小于0,自动偏移 + * @param yOffset y轴偏移量,yOffset小于0,自动偏移 + * @param radio 默认为原图的 1/4 + * @param alpha 透明度(0~1),PNG图片建议设置为1 + */ + public final static void pressImage(String watermarkImg, String srcImageFile, String destImageFile, int position, + int xOffset, int yOffset, float radio, float alpha) { + + if (notImageExtName(srcImageFile)) { + throw new IllegalArgumentException("只支持如下几种图片格式:jpg、jpeg、png、bmp"); + } + + try { + File img = new File(srcImageFile); + Image src = ImageIO.read(img); + int srcWidth = src.getWidth(null); + int srcHeight = src.getHeight(null); + + BufferedImage image = new BufferedImage(srcWidth, srcHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D graphics = image.createGraphics(); + graphics.drawImage(src, 0, 0, srcWidth, srcHeight, null); + + // 水印文件 + Image wmImage = ImageIO.read(new File(watermarkImg)); + int wmWidth = wmImage.getWidth(null); + int wmHeight = wmImage.getHeight(null); + + radio = radio <= 0 ? 0.2f : radio; + int newWidth = (int) (srcWidth * radio); + int newHeight = (int) (wmHeight * (newWidth / (float) wmWidth)); + + xOffset = (xOffset < 0) ? (int) (newWidth * 0.1f) : xOffset; + yOffset = (yOffset < 0) ? (int) (newHeight * 0.1f) : yOffset; + + int xPostion = 0; + int yPostion = 0; + + switch (position) { + case 1: + xPostion = xOffset; + yPostion = yOffset; + break; + case 2: + xPostion = (int) (srcWidth * (1 - radio) - xOffset); + yPostion = yOffset; + break; + case 3: + xPostion = (int) (srcWidth - newWidth) / 2; + yPostion = (int) (srcHeight - newHeight) / 2; + break; + case 4: + xPostion = xOffset; + yPostion = (int) (srcHeight - newHeight - yOffset); + break; + case 5: + xPostion = (int) (srcWidth * (1 - radio) - xOffset); + yPostion = (int) (srcHeight - newHeight - yOffset); + break; + default: + xPostion = xOffset; + yPostion = yOffset; + break; + } + + graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); + graphics.drawImage(wmImage, xPostion, yPostion, newWidth, newHeight, null); + // 水印文件结束 + graphics.dispose(); + + save(image, destImageFile); + + } catch (Exception e) { + log.warn("ImageUtils pressImage error", e); + } + } + + public static void zoom(int maxWidth, String srcImageFile, String destImageFile) { + try { + BufferedImage srcImage = ImageIO.read(new File(srcImageFile)); + int srcWidth = srcImage.getWidth(); + int srcHeight = srcImage.getHeight(); + + // 当宽度在 maxWidth 范围之内,直接copy + if (srcWidth <= maxWidth) { + FileUtils.copyFile(new File(srcImageFile), new File(destImageFile)); + } + // 当宽度超出 maxWidth 范围,将宽度变为 maxWidth,高度按比例缩放 + else { + float scalingRatio = (float) maxWidth / (float) srcWidth; // 计算缩放比率 + float maxHeight = ((float) srcHeight * scalingRatio); // 计算缩放后的高度 + BufferedImage ret = resize(srcImage, maxWidth, (int) maxHeight); + save(ret, destImageFile); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + /** + * 剪切 + * + * @param srcImageFile 原图 + * @param destImageFile 存放的目标位置 + * @param left 起始点:左 + * @param top 起始点:上 + * @param width 宽 + * @param height 高 + */ + public static void crop(String srcImageFile, String destImageFile, int left, int top, int width, int height) { + + if (notImageExtName(srcImageFile)) { + throw new IllegalArgumentException("只支持如下几种图片格式:jpg、jpeg、png、bmp"); + } + + try { + BufferedImage bi = ImageIO.read(new File(srcImageFile)); + width = Math.min(width, bi.getWidth()); + height = Math.min(height, bi.getHeight()); + if (width <= 0) { + width = bi.getWidth(); + } + if (height <= 0) { + height = bi.getHeight(); + } + + left = Math.min(Math.max(0, left), bi.getWidth() - width); + top = Math.min(Math.max(0, top), bi.getHeight() - height); + + BufferedImage subimage = bi.getSubimage(left, top, width, height); + BufferedImage resizeImage = resize(subimage, 200, 200); + + save(resizeImage, destImageFile); + + } catch (Exception e) { + log.error(e.toString(), e); + } + } + + + /** + * 高保真缩放 + */ + private static BufferedImage resize(BufferedImage bi, int toWidth, int toHeight) { + Graphics g = null; + try { + Image scaledImage = bi.getScaledInstance(toWidth, toHeight, Image.SCALE_SMOOTH); + BufferedImage ret = new BufferedImage(toWidth, toHeight, BufferedImage.TYPE_INT_RGB); + g = ret.getGraphics(); + g.drawImage(scaledImage, 0, 0, null); + return ret; + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (g != null) { + g.dispose(); + } + } + } + + + private static void save(BufferedImage bi, String outputImageFile) { + try { + ImageIO.write(bi, getExtName(outputImageFile), new File(outputImageFile)); + } catch (Exception e) { + log.error(e.toString(), e); + } + } + + } \ No newline at end of file diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/JPressJson.java b/jpress-commons/src/main/java/io/jpress/commons/utils/JPressJson.java index 3da22892c42e1cb6974b52de23787e01b54801f1..9b3d61458962c7dc0c8bd1518cda8ff0f7c9b676 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/JPressJson.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/JPressJson.java @@ -1,149 +1,149 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import com.alibaba.fastjson.JSON; -import com.google.common.collect.Lists; -import com.jfinal.json.JFinalJson; -import com.jfinal.kit.StrKit; -import com.jfinal.plugin.activerecord.Model; -import io.jboot.db.model.JbootModel; -import io.jpress.JPressOptions; - -import java.lang.reflect.Method; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 用于Json转化,但是移除所有null值的属性,内容更少 - * @Package io.jpress.commons.utils - */ -public class JPressJson extends JFinalJson { - - private static final List needAddDomainAttrs = Lists.newArrayList("avatar", "thumbnail"); - - - @Override - protected String mapToJson(Map map, int depth) { - roptimizeMapAttrs(map); - return map == null || map.isEmpty() ? "null" : super.mapToJson(map, depth); - } - - - /** - * 优化 map 的属性 - * - * @param map - */ - private void roptimizeMapAttrs(Map map) { - if (map == null) { - return; - } - String resDomain = JPressOptions.getResDomain(); - Iterator iter = map.entrySet().iterator(); - while (iter.hasNext()) { - - Map.Entry entry = (Map.Entry) iter.next(); - - //移除 null 值的属性 - if (entry.getValue() == null) { - iter.remove(); - continue; - } - - // 给图片类的属性,添加域名成为绝对路径, - // 相对路径放到app上去麻烦 - // 这个行为会改变model的值(涉及到改变缓存的值),所以应该由 以下 otherToJson() 方法进行拷贝 - if (resDomain != null && needAddDomainAttrs.contains(entry.getKey())) { - String value = (String) entry.getValue(); - if (!value.startsWith("http")) { - entry.setValue(resDomain + value); - } - } - - } - } - - @Override - protected String otherToJson(Object value, int depth) { - return value instanceof JbootModel - ? doRenderOtherToJson(((JbootModel) value).copy(), depth) - : doRenderOtherToJson(value, depth); - } - - - protected String doRenderOtherToJson(Object value, int depth) { - - if (value instanceof Model) { - Map map = com.jfinal.plugin.activerecord.CPI.getAttrs((Model) value); - addGetterAttrs(map, value); - return mapToJson(map, depth); - } - - return super.otherToJson(value, depth); - } - - /** - * 目的是 添加 getter 的值 - * - * @param map - * @param model - */ - protected void addGetterAttrs(Map map, Object model) { - Method[] methods = model.getClass().getDeclaredMethods(); - for (Method m : methods) { - String methodName = m.getName(); - int indexOfGet = methodName.indexOf("get"); - if (indexOfGet == 0 && methodName.length() > 3) { // Only getter - String attrName = methodName.substring(3); - if (!attrName.equals("Class")) { // Ignore Object.getClass() - Class[] types = m.getParameterTypes(); - if (types.length == 0) { - try { - Object value = m.invoke(model); - map.put(StrKit.firstCharToLowerCase(attrName), value); - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } - } - } - } else { - int indexOfIs = methodName.indexOf("is"); - if (indexOfIs == 0 && methodName.length() > 2) { - String attrName = methodName.substring(2); - Class[] types = m.getParameterTypes(); - if (types.length == 0) { - try { - Object value = m.invoke(model); - map.put(StrKit.firstCharToLowerCase(attrName), value); - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } - } - } - } - } - } - - - @Override - public T parse(String jsonString, Class type) { - return JSON.parseObject(jsonString, type); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import com.alibaba.fastjson.JSON; +import com.google.common.collect.Lists; +import com.jfinal.json.JFinalJson; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.Model; +import io.jboot.db.model.JbootModel; +import io.jpress.JPressOptions; + +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 用于Json转化,但是移除所有null值的属性,内容更少 + * @Package io.jpress.commons.utils + */ +public class JPressJson extends JFinalJson { + + private static final List needAddDomainAttrs = Lists.newArrayList("avatar", "thumbnail"); + + + @Override + protected String mapToJson(Map map, int depth) { + roptimizeMapAttrs(map); + return map == null || map.isEmpty() ? "null" : super.mapToJson(map, depth); + } + + + /** + * 优化 map 的属性 + * + * @param map + */ + private void roptimizeMapAttrs(Map map) { + if (map == null) { + return; + } + String resDomain = JPressOptions.getResDomain(); + Iterator iter = map.entrySet().iterator(); + while (iter.hasNext()) { + + Map.Entry entry = (Map.Entry) iter.next(); + + //移除 null 值的属性 + if (entry.getValue() == null) { + iter.remove(); + continue; + } + + // 给图片类的属性,添加域名成为绝对路径, + // 相对路径放到app上去麻烦 + // 这个行为会改变model的值(涉及到改变缓存的值),所以应该由 以下 otherToJson() 方法进行拷贝 + if (resDomain != null && needAddDomainAttrs.contains(entry.getKey())) { + String value = (String) entry.getValue(); + if (!value.startsWith("http")) { + entry.setValue(resDomain + value); + } + } + + } + } + + @Override + protected String otherToJson(Object value, int depth) { + return value instanceof JbootModel + ? doRenderOtherToJson(((JbootModel) value).copy(), depth) + : doRenderOtherToJson(value, depth); + } + + + protected String doRenderOtherToJson(Object value, int depth) { + + if (value instanceof Model) { + Map map = com.jfinal.plugin.activerecord.CPI.getAttrs((Model) value); + addGetterAttrs(map, value); + return mapToJson(map, depth); + } + + return super.otherToJson(value, depth); + } + + /** + * 目的是 添加 getter 的值 + * + * @param map + * @param model + */ + protected void addGetterAttrs(Map map, Object model) { + Method[] methods = model.getClass().getDeclaredMethods(); + for (Method m : methods) { + String methodName = m.getName(); + int indexOfGet = methodName.indexOf("get"); + if (indexOfGet == 0 && methodName.length() > 3) { // Only getter + String attrName = methodName.substring(3); + if (!attrName.equals("Class")) { // Ignore Object.getClass() + Class[] types = m.getParameterTypes(); + if (types.length == 0) { + try { + Object value = m.invoke(model); + map.put(StrKit.firstCharToLowerCase(attrName), value); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + } + } else { + int indexOfIs = methodName.indexOf("is"); + if (indexOfIs == 0 && methodName.length() > 2) { + String attrName = methodName.substring(2); + Class[] types = m.getParameterTypes(); + if (types.length == 0) { + try { + Object value = m.invoke(model); + map.put(StrKit.firstCharToLowerCase(attrName), value); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + } + } + } + } + + + @Override + public T parse(String jsonString, Class type) { + return JSON.parseObject(jsonString, type); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/JsoupUtils.java b/jpress-commons/src/main/java/io/jpress/commons/utils/JsoupUtils.java index f08808e71c75a2aab1a8dab15a9183e5c896758c..0b948f4ffd59baedfd5d7e6ba3a1fcabd17acd5e 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/JsoupUtils.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/JsoupUtils.java @@ -1,177 +1,177 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import com.jfinal.plugin.activerecord.Model; -import io.jboot.utils.StrUtil; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Attribute; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import java.util.ArrayList; -import java.util.List; - -public class JsoupUtils { - - - public static String getFirstImageSrc(String html) { - return getFirstQuerySrc(html, "img"); - } - - public static String getFirstVideoSrc(String html) { - return getFirstQuerySrc(html, "video"); - } - - public static String getFirstAudioSrc(String html) { - return getFirstQuerySrc(html, "audio"); - } - - public static String getFirstQuerySrc(String html, String query) { - if (StrUtil.isBlank(html)) { - return null; - } - - Elements es = Jsoup.parseBodyFragment(html).select(query); - if (es != null && es.size() > 0) { - String src = es.first().attr("src"); - return StrUtil.isBlank(src) ? null : src; - } - - return null; - } - - - public static List getImageSrcs(String html) { - if (StrUtil.isBlank(html)) { - return null; - } - - List list = new ArrayList(); - - Document doc = Jsoup.parseBodyFragment(html); - Elements es = doc.select("img"); - if (es != null && es.size() > 0) { - for (Element e : es) { - String src = e.attr("src"); - if (StrUtil.isNotBlank(src)) { - list.add(src); - } - } - } - return list.isEmpty() ? null : list; - } - - - public static String getText(String html) { - if (StrUtil.isBlank(html)) { - return html; - } - return StrUtil.escapeHtml(Jsoup.parse(html).text()); - } - - public static void clean(Model model, String... attrs) { - if (attrs != null && attrs.length == 0) { - return; - } - - for (String attr : attrs) { - Object data = model.get(attr); - if (data == null || !(data instanceof String)) { - continue; - } - - model.set(attr, clean((String) data)); - } - } - - private static MyWhitelist whitelist = new MyWhitelist(); - - public static String clean(String html) { - if (StrUtil.isNotBlank(html)) { - return Jsoup.clean(html, whitelist); - } - - return html; - } - - /** - * 做自己的白名单,允许base64的图片通过等 - * - * @author michael - */ - public static class MyWhitelist extends org.jsoup.safety.Whitelist { - - public MyWhitelist() { - - addTags("a", "b", "blockquote", "br", "caption", "cite", "code", "col", "colgroup", "dd", "div", "span", "embed", "object", "dl", "dt", - "em", "h1", "h2", "h3", "h4", "h5", "h6", "i", "img", "li", "ol", "p", "pre", "q", "small", - "strike", "strong", "sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "u", "ul"); - - addAttributes("a", "href", "title", "target"); - addAttributes("blockquote", "cite"); - addAttributes("col", "span"); - addAttributes("colgroup", "span"); - addAttributes("img", "align", "alt", "src", "title"); - addAttributes("ol", "start"); - addAttributes("q", "cite"); - addAttributes("table", "summary"); - addAttributes("td", "abbr", "axis", "colspan", "rowspan", "width"); - addAttributes("th", "abbr", "axis", "colspan", "rowspan", "scope", "width"); - addAttributes("video", "src", "autoplay", "controls", "loop", "muted", "poster", "preload"); - addAttributes("object", "width", "height", "classid", "codebase"); - addAttributes("param", "name", "value"); - addAttributes("embed", "src", "quality", "width", "height", "allowFullScreen", "allowScriptAccess", "flashvars", "name", "type", "pluginspage"); - - addAttributes(":all", "class", "style", "height", "width", "type", "id", "name"); - -// - addProtocols("blockquote", "cite", "http", "https"); - addProtocols("cite", "cite", "http", "https"); - addProtocols("q", "cite", "http", "https"); - - //如果添加以下的协议,那么href 必须是http、 https 等开头,相对路径则被过滤掉了 - //addProtocols("a", "href", "ftp", "http", "https", "mailto", "tel"); - - //如果添加以下的协议,那么src必须是http 或者 https 开头,相对路径则被过滤掉了, - //所以必须注释掉,允许相对路径的图片资源 - //addProtocols("img", "src", "http", "https"); - } - - @Override - protected boolean isSafeAttribute(String tagName, Element el, Attribute attr) { - - //不允许 javascript 开头的 src 和 href - if ("src".equalsIgnoreCase(attr.getKey()) || "href".equalsIgnoreCase(attr.getKey())) { - String value = attr.getValue(); - if (StrUtil.isNotBlank(value) && value.toLowerCase().startsWith("javascript")) { - return false; - } - } - - - //允许 base64 的图片内容 - if ("img".equals(tagName) && "src".equals(attr.getKey()) && attr.getValue().startsWith("data:;base64")){ - return true; - } - - return super.isSafeAttribute(tagName, el, attr); - } - } - - +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import com.jfinal.plugin.activerecord.Model; +import io.jboot.utils.StrUtil; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Attribute; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.util.ArrayList; +import java.util.List; + +public class JsoupUtils { + + + public static String getFirstImageSrc(String html) { + return getFirstQuerySrc(html, "img"); + } + + public static String getFirstVideoSrc(String html) { + return getFirstQuerySrc(html, "video"); + } + + public static String getFirstAudioSrc(String html) { + return getFirstQuerySrc(html, "audio"); + } + + public static String getFirstQuerySrc(String html, String query) { + if (StrUtil.isBlank(html)) { + return null; + } + + Elements es = Jsoup.parseBodyFragment(html).select(query); + if (es != null && es.size() > 0) { + String src = es.first().attr("src"); + return StrUtil.isBlank(src) ? null : src; + } + + return null; + } + + + public static List getImageSrcs(String html) { + if (StrUtil.isBlank(html)) { + return null; + } + + List list = new ArrayList(); + + Document doc = Jsoup.parseBodyFragment(html); + Elements es = doc.select("img"); + if (es != null && es.size() > 0) { + for (Element e : es) { + String src = e.attr("src"); + if (StrUtil.isNotBlank(src)) { + list.add(src); + } + } + } + return list.isEmpty() ? null : list; + } + + + public static String getText(String html) { + if (StrUtil.isBlank(html)) { + return html; + } + return StrUtil.escapeHtml(Jsoup.parse(html).text()); + } + + public static void clean(Model model, String... attrs) { + if (attrs != null && attrs.length == 0) { + return; + } + + for (String attr : attrs) { + Object data = model.get(attr); + if (data == null || !(data instanceof String)) { + continue; + } + + model.set(attr, clean((String) data)); + } + } + + private static MyWhitelist whitelist = new MyWhitelist(); + + public static String clean(String html) { + if (StrUtil.isNotBlank(html)) { + return Jsoup.clean(html, whitelist); + } + + return html; + } + + /** + * 做自己的白名单,允许base64的图片通过等 + * + * @author michael + */ + public static class MyWhitelist extends org.jsoup.safety.Whitelist { + + public MyWhitelist() { + + addTags("a", "b", "blockquote", "br", "caption", "cite", "code", "col", "colgroup", "dd", "div", "span", "embed", "object", "dl", "dt", + "em", "h1", "h2", "h3", "h4", "h5", "h6", "i", "img", "li", "ol", "p", "pre", "q", "small", + "strike", "strong", "sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "u", "ul"); + + addAttributes("a", "href", "title", "target"); + addAttributes("blockquote", "cite"); + addAttributes("col", "span"); + addAttributes("colgroup", "span"); + addAttributes("img", "align", "alt", "src", "title"); + addAttributes("ol", "start"); + addAttributes("q", "cite"); + addAttributes("table", "summary"); + addAttributes("td", "abbr", "axis", "colspan", "rowspan", "width"); + addAttributes("th", "abbr", "axis", "colspan", "rowspan", "scope", "width"); + addAttributes("video", "src", "autoplay", "controls", "loop", "muted", "poster", "preload"); + addAttributes("object", "width", "height", "classid", "codebase"); + addAttributes("param", "name", "value"); + addAttributes("embed", "src", "quality", "width", "height", "allowFullScreen", "allowScriptAccess", "flashvars", "name", "type", "pluginspage"); + + addAttributes(":all", "class", "style", "height", "width", "type", "id", "name"); + +// + addProtocols("blockquote", "cite", "http", "https"); + addProtocols("cite", "cite", "http", "https"); + addProtocols("q", "cite", "http", "https"); + + //如果添加以下的协议,那么href 必须是http、 https 等开头,相对路径则被过滤掉了 + //addProtocols("a", "href", "ftp", "http", "https", "mailto", "tel"); + + //如果添加以下的协议,那么src必须是http 或者 https 开头,相对路径则被过滤掉了, + //所以必须注释掉,允许相对路径的图片资源 + //addProtocols("img", "src", "http", "https"); + } + + @Override + protected boolean isSafeAttribute(String tagName, Element el, Attribute attr) { + + //不允许 javascript 开头的 src 和 href + if ("src".equalsIgnoreCase(attr.getKey()) || "href".equalsIgnoreCase(attr.getKey())) { + String value = attr.getValue(); + if (StrUtil.isNotBlank(value) && value.toLowerCase().startsWith("javascript")) { + return false; + } + } + + + //允许 base64 的图片内容 + if ("img".equals(tagName) && "src".equals(attr.getKey()) && attr.getValue().startsWith("data:;base64")){ + return true; + } + + return super.isSafeAttribute(tagName, el, attr); + } + } + + } \ No newline at end of file diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/MarkdownUtils.java b/jpress-commons/src/main/java/io/jpress/commons/utils/MarkdownUtils.java index 0ca59056e12dcde58329953a68afdd61ac6f2ba1..beda1dcc4215405870cc82352029e52ffc61f1a4 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/MarkdownUtils.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/MarkdownUtils.java @@ -1,108 +1,108 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import io.jboot.utils.StrUtil; -import org.commonmark.Extension; -import org.commonmark.ext.front.matter.YamlFrontMatterExtension; -import org.commonmark.ext.front.matter.YamlFrontMatterVisitor; -import org.commonmark.ext.gfm.tables.TablesExtension; -import org.commonmark.node.Node; -import org.commonmark.parser.Parser; -import org.commonmark.renderer.html.HtmlRenderer; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @author Ryan Wang(i@ryanc.cc) - * @version V1.1 - * @Title: Markdown 工具类 - * @Package io.jpress.commons.utils - */ -public class MarkdownUtils { - - /** - * Front-matter插件 - */ - private static final Set EXTENSIONS_YAML = Collections.singleton(YamlFrontMatterExtension.create()); - - /** - * Table插件 - */ - private static final Set EXTENSIONS_TABLE = Collections.singleton(TablesExtension.create()); - - /** - * 解析Markdown文档 - */ - private static final Parser PARSER = Parser.builder() - .extensions(EXTENSIONS_YAML) - .extensions(EXTENSIONS_TABLE) - .build(); - - /** - * 渲染HTML文档 - */ - private static final HtmlRenderer RENDERER = HtmlRenderer.builder() -// .nodeRendererFactory(context -> new IndentedCodeBlockNodeRenderer(context)) - .extensions(EXTENSIONS_YAML) - .extensions(EXTENSIONS_TABLE) - .build(); - - - /** - * 渲染html - * - * @param markdown markdown格式文本 - * @return html文本 - */ - public static String toHtml(String markdown) { - if (StrUtil.isBlank(markdown)) { - return markdown; - } - Node document = PARSER.parse(markdown); - return RENDERER.render(document); - } - - /** - * 获取元数据 - * - * @param content content - * @return Map - */ - public static Map> getFrontMatter(String content) { - YamlFrontMatterVisitor visitor = new YamlFrontMatterVisitor(); - Node document = PARSER.parse(content); - document.accept(visitor); - return visitor.getData(); - } - - - public static void main(String[] args) { - - String markdown = "This is *Sparta* : `aaa` \n\n```\naaa\n```\n\n"; - - long ctime = System.currentTimeMillis(); - for (int i = 0; i < 100000; i++) { - toHtml(markdown); - } - System.out.println("100000 times : " + (System.currentTimeMillis() - ctime)); - System.out.println(toHtml(markdown)); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import io.jboot.utils.StrUtil; +import org.commonmark.Extension; +import org.commonmark.ext.front.matter.YamlFrontMatterExtension; +import org.commonmark.ext.front.matter.YamlFrontMatterVisitor; +import org.commonmark.ext.gfm.tables.TablesExtension; +import org.commonmark.node.Node; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @author Ryan Wang(i@ryanc.cc) + * @version V1.1 + * @Title: Markdown 工具类 + * @Package io.jpress.commons.utils + */ +public class MarkdownUtils { + + /** + * Front-matter插件 + */ + private static final Set EXTENSIONS_YAML = Collections.singleton(YamlFrontMatterExtension.create()); + + /** + * Table插件 + */ + private static final Set EXTENSIONS_TABLE = Collections.singleton(TablesExtension.create()); + + /** + * 解析Markdown文档 + */ + private static final Parser PARSER = Parser.builder() + .extensions(EXTENSIONS_YAML) + .extensions(EXTENSIONS_TABLE) + .build(); + + /** + * 渲染HTML文档 + */ + private static final HtmlRenderer RENDERER = HtmlRenderer.builder() +// .nodeRendererFactory(context -> new IndentedCodeBlockNodeRenderer(context)) + .extensions(EXTENSIONS_YAML) + .extensions(EXTENSIONS_TABLE) + .build(); + + + /** + * 渲染html + * + * @param markdown markdown格式文本 + * @return html文本 + */ + public static String toHtml(String markdown) { + if (StrUtil.isBlank(markdown)) { + return markdown; + } + Node document = PARSER.parse(markdown); + return RENDERER.render(document); + } + + /** + * 获取元数据 + * + * @param content content + * @return Map + */ + public static Map> getFrontMatter(String content) { + YamlFrontMatterVisitor visitor = new YamlFrontMatterVisitor(); + Node document = PARSER.parse(content); + document.accept(visitor); + return visitor.getData(); + } + + + public static void main(String[] args) { + + String markdown = "This is *Sparta* : `aaa` \n\n```\naaa\n```\n\n"; + + long ctime = System.currentTimeMillis(); + for (int i = 0; i < 100000; i++) { + toHtml(markdown); + } + System.out.println("100000 times : " + (System.currentTimeMillis() - ctime)); + System.out.println(toHtml(markdown)); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/SignUtils.java b/jpress-commons/src/main/java/io/jpress/commons/utils/SignUtils.java index 5d665b418c899d33ed4ca09f71cc2e3f32e6216c..10f1f856b3c9f61d3fd560de3aeb660e24e116a2 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/SignUtils.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/SignUtils.java @@ -1,45 +1,45 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import com.jfinal.kit.HashKit; -import io.jboot.utils.StrUtil; - -import java.util.Arrays; -import java.util.Map; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Package io.jpress.commons.utils - */ -public class SignUtils { - - public static String signForRequest(Map params, String secret) { - String[] keys = params.keySet().toArray(new String[0]); - Arrays.sort(keys); - - StringBuilder query = new StringBuilder(); - for (String key : keys) { - String value = params.get(key); - if (StrUtil.areNotEmpty(key, value)) { - query.append(key).append(value); - } - } - query.append(secret); - return HashKit.md5(query.toString()); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import com.jfinal.kit.HashKit; +import io.jboot.utils.StrUtil; + +import java.util.Arrays; +import java.util.Map; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Package io.jpress.commons.utils + */ +public class SignUtils { + + public static String signForRequest(Map params, String secret) { + String[] keys = params.keySet().toArray(new String[0]); + Arrays.sort(keys); + + StringBuilder query = new StringBuilder(); + for (String key : keys) { + String value = params.get(key); + if (StrUtil.areNotEmpty(key, value)) { + query.append(key).append(value); + } + } + query.append(secret); + return HashKit.md5(query.toString()); + } +} diff --git a/jpress-commons/src/main/java/io/jpress/commons/utils/SqlUtils.java b/jpress-commons/src/main/java/io/jpress/commons/utils/SqlUtils.java index 3e2ae59b0299034b106e5c825a495efa1dfbafb6..32eb570268fb5420aa5740d4cade2511853e03c6 100644 --- a/jpress-commons/src/main/java/io/jpress/commons/utils/SqlUtils.java +++ b/jpress-commons/src/main/java/io/jpress/commons/utils/SqlUtils.java @@ -1,74 +1,74 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.commons.utils; - -import io.jboot.db.model.Columns; -import io.jboot.db.model.SqlBuilder; -import io.jboot.utils.StrUtil; - -import java.util.Date; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Package io.jpress.commons.utils - */ -public class SqlUtils { - - public static String toWhereSql(Columns columns) { - if (columns == null || columns.isEmpty()){ - return ""; - } - - StringBuilder sql = new StringBuilder(); - SqlBuilder.buildWhereSql(sql,columns.getList(),' '); - return sql.toString(); - } - - public static String buildInSqlPara(Object... ids) { - int iMax = ids.length - 1; - StringBuilder b = new StringBuilder(); - b.append('('); - for (int i = 0; ; i++) { - String id = String.valueOf(ids[i]); - if (!StrUtil.isNumeric(id)) { - throw new IllegalArgumentException("id must is numeric"); - } - b.append(id); - if (i == iMax) { - return b.append(')').toString(); - } - b.append(", "); - } - } - - - public static void main(String[] args){ - Columns columns = Columns.create(); - columns.eq("a.id",1); - System.out.println(toWhereSql(columns)); - - columns.in("c.id",1,2,4,5); - System.out.println(toWhereSql(columns)); - - columns.or(); - columns.between("created",new Date(),new Date()); - System.out.println(toWhereSql(columns)); - } - - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.commons.utils; + +import io.jboot.db.model.Columns; +import io.jboot.db.model.SqlBuilder; +import io.jboot.utils.StrUtil; + +import java.util.Date; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Package io.jpress.commons.utils + */ +public class SqlUtils { + + public static String toWhereSql(Columns columns) { + if (columns == null || columns.isEmpty()){ + return ""; + } + + StringBuilder sql = new StringBuilder(); + SqlBuilder.buildWhereSql(sql,columns.getList(),' '); + return sql.toString(); + } + + public static String buildInSqlPara(Object... ids) { + int iMax = ids.length - 1; + StringBuilder b = new StringBuilder(); + b.append('('); + for (int i = 0; ; i++) { + String id = String.valueOf(ids[i]); + if (!StrUtil.isNumeric(id)) { + throw new IllegalArgumentException("id must is numeric"); + } + b.append(id); + if (i == iMax) { + return b.append(')').toString(); + } + b.append(", "); + } + } + + + public static void main(String[] args){ + Columns columns = Columns.create(); + columns.eq("a.id",1); + System.out.println(toWhereSql(columns)); + + columns.in("c.id",1,2,4,5); + System.out.println(toWhereSql(columns)); + + columns.or(); + columns.between("created",new Date(),new Date()); + System.out.println(toWhereSql(columns)); + } + + + +} diff --git a/jpress-core/pom.xml b/jpress-core/pom.xml index 3a1d7467991fdc9d06f0ff447deb659f97a54c3b..42a82198f51dcd0358cbb030c0170d486b0842a5 100644 --- a/jpress-core/pom.xml +++ b/jpress-core/pom.xml @@ -1,82 +1,82 @@ - - - - io.jpress - parent - 3.0 - - 4.0.0 - - io.jpress - jpress-core - - - - - io.jboot - jboot - - - - com.jfinal - jfinal-weixin - - - - io.jpress - jpress-model - - - - io.jpress - jpress-service-api - - - - io.jpress - jpress-commons - - - - commons-io - commons-io - - - - ch.qos.logback - logback-core - - - - ch.qos.logback - logback-classic - - - - - junit - junit - 4.12 - test - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - - - + + + + io.jpress + parent + 3.0 + + 4.0.0 + + io.jpress + jpress-core + + + + + io.jboot + jboot + + + + com.jfinal + jfinal-weixin + + + + io.jpress + jpress-model + + + + io.jpress + jpress-service-api + + + + io.jpress + jpress-commons + + + + commons-io + commons-io + + + + ch.qos.logback + logback-core + + + + ch.qos.logback + logback-classic + + + + + junit + junit + 4.12 + test + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + \ No newline at end of file diff --git a/jpress-core/src/main/java/io/jpress/JPressCoreInitializer.java b/jpress-core/src/main/java/io/jpress/JPressCoreInitializer.java index 649c58ca8b4590213083b008d2396edf3294a9a9..21aebb68a69373ea8d46783b8945b18ca5b6349d 100644 --- a/jpress-core/src/main/java/io/jpress/JPressCoreInitializer.java +++ b/jpress-core/src/main/java/io/jpress/JPressCoreInitializer.java @@ -1,120 +1,120 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress; - -import com.jfinal.config.Constants; -import com.jfinal.config.Interceptors; -import com.jfinal.config.Routes; -import com.jfinal.kit.PathKit; -import com.jfinal.template.Engine; -import io.jboot.aop.jfinal.JfinalHandlers; -import io.jboot.core.listener.JbootAppListenerBase; -import io.jboot.web.fixedinterceptor.FixedInterceptors; -import io.jpress.commons.utils.JPressJson; -import io.jpress.core.addon.AddonManager; -import io.jpress.core.addon.controller.AddonControllerProcesser; -import io.jpress.core.addon.handler.AddonHandlerProcesser; -import io.jpress.core.addon.interceptor.AddonInterceptorProcesser; -import io.jpress.core.install.InstallHandler; -import io.jpress.core.menu.MenuManager; -import io.jpress.core.support.ehcache.EhcacheManager; -import io.jpress.core.wechat.WechatAddonManager; -import io.jpress.web.captcha.JPressCaptchaCache; -import io.jpress.web.functions.JPressCoreFunctions; -import io.jpress.web.handler.JPressHandler; -import io.jpress.web.interceptor.JPressInterceptor; -import io.jpress.web.interceptor.UTMInterceptor; -import io.jpress.web.render.JPressRenderFactory; -import io.jpress.web.sitemap.SitemapHandler; -import io.jpress.web.sitemap.SitemapManager; - -import java.net.URISyntaxException; -import java.net.URL; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 初始化工具 - * @Package io.jpress - */ -public class JPressCoreInitializer extends JbootAppListenerBase { - - @Override - public void onInit() { - try { - URL resourceUrl = JPressCoreInitializer.class.getResource("/"); - if (resourceUrl != null) { - PathKit.setWebRootPath(resourceUrl.toURI().getPath()); - } - EhcacheManager.init(); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - } - - - @Override - public void onConstantConfig(Constants constants) { - - constants.setRenderFactory(new JPressRenderFactory()); - constants.setCaptchaCache(new JPressCaptchaCache()); - constants.setJsonFactory(() -> new JPressJson()); - - } - - @Override - public void onRouteConfig(Routes routes) { - routes.setClearAfterMapping(false); - } - - @Override - public void onFixedInterceptorConfig(FixedInterceptors fixedInterceptors) { - fixedInterceptors.add(new AddonInterceptorProcesser()); - } - - - @Override - public void onHandlerConfig(JfinalHandlers handlers) { - handlers.add(new InstallHandler()); - handlers.add(new SitemapHandler()); - handlers.add(new JPressHandler()); - handlers.add(new AddonHandlerProcesser()); - - handlers.setActionHandler(new AddonControllerProcesser()); - } - - @Override - public void onEngineConfig(Engine engine) { - engine.addSharedStaticMethod(JPressCoreFunctions.class); - } - - @Override - public void onInterceptorConfig(Interceptors interceptors) { - interceptors.add(new UTMInterceptor()); - interceptors.add(new JPressInterceptor()); - } - - @Override - public void onStart() { - - SitemapManager.me().init(); - MenuManager.me().init(); - WechatAddonManager.me().init(); - AddonManager.me().init(); - - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress; + +import com.jfinal.config.Constants; +import com.jfinal.config.Interceptors; +import com.jfinal.config.Routes; +import com.jfinal.kit.PathKit; +import com.jfinal.template.Engine; +import io.jboot.aop.jfinal.JfinalHandlers; +import io.jboot.core.listener.JbootAppListenerBase; +import io.jboot.web.fixedinterceptor.FixedInterceptors; +import io.jpress.commons.utils.JPressJson; +import io.jpress.core.addon.AddonManager; +import io.jpress.core.addon.controller.AddonControllerProcesser; +import io.jpress.core.addon.handler.AddonHandlerProcesser; +import io.jpress.core.addon.interceptor.AddonInterceptorProcesser; +import io.jpress.core.install.InstallHandler; +import io.jpress.core.menu.MenuManager; +import io.jpress.core.support.ehcache.EhcacheManager; +import io.jpress.core.wechat.WechatAddonManager; +import io.jpress.web.captcha.JPressCaptchaCache; +import io.jpress.web.functions.JPressCoreFunctions; +import io.jpress.web.handler.JPressHandler; +import io.jpress.web.interceptor.JPressInterceptor; +import io.jpress.web.interceptor.UTMInterceptor; +import io.jpress.web.render.JPressRenderFactory; +import io.jpress.web.sitemap.SitemapHandler; +import io.jpress.web.sitemap.SitemapManager; + +import java.net.URISyntaxException; +import java.net.URL; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 初始化工具 + * @Package io.jpress + */ +public class JPressCoreInitializer extends JbootAppListenerBase { + + @Override + public void onInit() { + try { + URL resourceUrl = JPressCoreInitializer.class.getResource("/"); + if (resourceUrl != null) { + PathKit.setWebRootPath(resourceUrl.toURI().getPath()); + } + EhcacheManager.init(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + + + @Override + public void onConstantConfig(Constants constants) { + + constants.setRenderFactory(new JPressRenderFactory()); + constants.setCaptchaCache(new JPressCaptchaCache()); + constants.setJsonFactory(() -> new JPressJson()); + + } + + @Override + public void onRouteConfig(Routes routes) { + routes.setClearAfterMapping(false); + } + + @Override + public void onFixedInterceptorConfig(FixedInterceptors fixedInterceptors) { + fixedInterceptors.add(new AddonInterceptorProcesser()); + } + + + @Override + public void onHandlerConfig(JfinalHandlers handlers) { + handlers.add(new InstallHandler()); + handlers.add(new SitemapHandler()); + handlers.add(new JPressHandler()); + handlers.add(new AddonHandlerProcesser()); + + handlers.setActionHandler(new AddonControllerProcesser()); + } + + @Override + public void onEngineConfig(Engine engine) { + engine.addSharedStaticMethod(JPressCoreFunctions.class); + } + + @Override + public void onInterceptorConfig(Interceptors interceptors) { + interceptors.add(new UTMInterceptor()); + interceptors.add(new JPressInterceptor()); + } + + @Override + public void onStart() { + + SitemapManager.me().init(); + MenuManager.me().init(); + WechatAddonManager.me().init(); + AddonManager.me().init(); + + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/Addon.java b/jpress-core/src/main/java/io/jpress/core/addon/Addon.java index 6a9ea280d9b3a043cbb0afa2d42d1a188d3555b0..6af49e38eeab7fdfd0d467665e930ffc5760a29c 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/Addon.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/Addon.java @@ -1,31 +1,31 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon; - -/** - * 插件(扩展)的接口 - */ -public interface Addon { - - public void onInstall(AddonInfo addonInfo); - - public void onUninstall(AddonInfo addonInfo); - - public void onStart(AddonInfo addonInfo); - - public void onStop(AddonInfo addonInfo); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon; + +/** + * 插件(扩展)的接口 + */ +public interface Addon { + + public void onInstall(AddonInfo addonInfo); + + public void onUninstall(AddonInfo addonInfo); + + public void onStart(AddonInfo addonInfo); + + public void onStop(AddonInfo addonInfo); + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/AddonClassLoader.java b/jpress-core/src/main/java/io/jpress/core/addon/AddonClassLoader.java index 2c1a61ccc89e500196f32c650f2a01f739faa961..a709e731e9de3af87d9227d86eb81fc2c088fc7f 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/AddonClassLoader.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/AddonClassLoader.java @@ -1,193 +1,193 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon; - - -import com.google.common.collect.Lists; -import com.jfinal.aop.AopManager; -import com.jfinal.aop.Interceptor; -import com.jfinal.core.Controller; -import com.jfinal.handler.Handler; -import com.jfinal.log.Log; -import com.jfinal.template.Directive; -import io.jboot.aop.annotation.Bean; -import io.jboot.aop.annotation.BeanExclude; -import io.jboot.components.event.JbootEventListener; -import io.jboot.components.mq.JbootmqMessageListener; -import io.jboot.db.model.JbootModel; -import io.jboot.utils.ArrayUtil; -import io.jpress.core.addon.annotation.GlobalInterceptor; -import io.jpress.core.wechat.WechatAddon; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.zip.ZipEntry; - -public class AddonClassLoader extends URLClassLoader { - - private static final Log LOG = Log.getLog(AddonClassLoader.class); - - private AddonInfo addonInfo; - private List classNameList; - - public AddonClassLoader(AddonInfo addonInfo) throws IOException { - super(new URL[]{}, Thread.currentThread().getContextClassLoader()); - this.addURL(addonInfo.buildJarFile().toURI().toURL()); - this.addonInfo = addonInfo; - this.classNameList = new ArrayList<>(); - this.initClassNameList(); - } - - public List getClassNameList() { - return classNameList; - } - - private void initClassNameList() throws IOException { - Enumeration entries = new JarFile(addonInfo.buildJarFile()).entries(); - while (entries.hasMoreElements()) { - JarEntry jarEntry = entries.nextElement(); - String entryName = jarEntry.getName(); - if (!jarEntry.isDirectory() && entryName.endsWith(".class")) { - String className = entryName.replace("/", ".").substring(0, entryName.length() - 6); - classNameList.add(className); - } - } - } - - public void load() { - for (String className : classNameList) { - try { - - Class loadedClass = loadClass(className); - - Bean bean = (Bean) loadedClass.getDeclaredAnnotation(Bean.class); - if (bean != null) { - initBeanMapping(loadedClass); - } - - // controllers - if (Controller.class.isAssignableFrom(loadedClass)) { - addonInfo.addController(loadedClass); - } - // interceptors - else if (Interceptor.class.isAssignableFrom(loadedClass)) { - if (loadedClass.getAnnotation(GlobalInterceptor.class) != null) { - addonInfo.addInterceptor(loadedClass); - } - } - // handlers - else if (Handler.class.isAssignableFrom(loadedClass)) { - addonInfo.addHandler(loadedClass); - } - // models - else if (JbootModel.class.isAssignableFrom(loadedClass)) { - addonInfo.addModel(loadedClass); - } - // directives - else if (Directive.class.isAssignableFrom(loadedClass)) { - addonInfo.addDirective(loadedClass); - } - // wechatAddons - else if (WechatAddon.class.isAssignableFrom(loadedClass)) { - addonInfo.addWechatAddon(loadedClass); - } - // addonClass - else if (Addon.class.isAssignableFrom(loadedClass)) { - addonInfo.setAddonClass(loadedClass); - } - // upgraderClass - else if (AddonUpgrader.class.isAssignableFrom(loadedClass)) { - addonInfo.setUpgraderClass(loadedClass); - } - - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - } - } - - - private static Class[] default_excludes = new Class[]{JbootEventListener.class, JbootmqMessageListener.class, Serializable.class}; - - /** - * 初始化 @Bean 注解的映射关系 - */ - private void initBeanMapping(Class implClass) { - - Class[] interfaceClasses = implClass.getInterfaces(); - - if (interfaceClasses == null || interfaceClasses.length == 0) { - return; - } - - Class[] excludes = buildExcludeClasses(implClass); - - for (Class interfaceClass : interfaceClasses) { - if (inExcludes(interfaceClass, excludes) == false) { - AopManager.me().addMapping(interfaceClass, implClass); - } - } - } - - private Class[] buildExcludeClasses(Class implClass) { - BeanExclude beanExclude = (BeanExclude) implClass.getAnnotation(BeanExclude.class); - - //对某些系统的类 进行排除,例如:Serializable 等 - return beanExclude == null - ? default_excludes - : ArrayUtil.concat(default_excludes, beanExclude.value()); - } - - private boolean inExcludes(Class interfaceClass, Class[] excludes) { - for (Class ex : excludes) { - if (ex.isAssignableFrom(interfaceClass)) { - return true; - } - } - return false; - } - - static final List SUPPORT_NATIVE_SUFFIXES = Lists.newArrayList(".so", ".dylib", ".dll"); - - @Override - public InputStream getResourceAsStream(String name) { - InputStream superStream = super.getResourceAsStream(name); - int dotLastIndex = name.lastIndexOf("."); - if (dotLastIndex > -1) { - String suffix = name.substring(dotLastIndex); - boolean isSupport = SUPPORT_NATIVE_SUFFIXES.contains(suffix); - if (superStream == null && isSupport) { - try { - ZipEntry zipEntry = new ZipEntry(name); - return new JarFile(addonInfo.buildJarFile()).getInputStream(zipEntry); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - } - return superStream; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon; + + +import com.google.common.collect.Lists; +import com.jfinal.aop.AopManager; +import com.jfinal.aop.Interceptor; +import com.jfinal.core.Controller; +import com.jfinal.handler.Handler; +import com.jfinal.log.Log; +import com.jfinal.template.Directive; +import io.jboot.aop.annotation.Bean; +import io.jboot.aop.annotation.BeanExclude; +import io.jboot.components.event.JbootEventListener; +import io.jboot.components.mq.JbootmqMessageListener; +import io.jboot.db.model.JbootModel; +import io.jboot.utils.ArrayUtil; +import io.jpress.core.addon.annotation.GlobalInterceptor; +import io.jpress.core.wechat.WechatAddon; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +public class AddonClassLoader extends URLClassLoader { + + private static final Log LOG = Log.getLog(AddonClassLoader.class); + + private AddonInfo addonInfo; + private List classNameList; + + public AddonClassLoader(AddonInfo addonInfo) throws IOException { + super(new URL[]{}, Thread.currentThread().getContextClassLoader()); + this.addURL(addonInfo.buildJarFile().toURI().toURL()); + this.addonInfo = addonInfo; + this.classNameList = new ArrayList<>(); + this.initClassNameList(); + } + + public List getClassNameList() { + return classNameList; + } + + private void initClassNameList() throws IOException { + Enumeration entries = new JarFile(addonInfo.buildJarFile()).entries(); + while (entries.hasMoreElements()) { + JarEntry jarEntry = entries.nextElement(); + String entryName = jarEntry.getName(); + if (!jarEntry.isDirectory() && entryName.endsWith(".class")) { + String className = entryName.replace("/", ".").substring(0, entryName.length() - 6); + classNameList.add(className); + } + } + } + + public void load() { + for (String className : classNameList) { + try { + + Class loadedClass = loadClass(className); + + Bean bean = (Bean) loadedClass.getDeclaredAnnotation(Bean.class); + if (bean != null) { + initBeanMapping(loadedClass); + } + + // controllers + if (Controller.class.isAssignableFrom(loadedClass)) { + addonInfo.addController(loadedClass); + } + // interceptors + else if (Interceptor.class.isAssignableFrom(loadedClass)) { + if (loadedClass.getAnnotation(GlobalInterceptor.class) != null) { + addonInfo.addInterceptor(loadedClass); + } + } + // handlers + else if (Handler.class.isAssignableFrom(loadedClass)) { + addonInfo.addHandler(loadedClass); + } + // models + else if (JbootModel.class.isAssignableFrom(loadedClass)) { + addonInfo.addModel(loadedClass); + } + // directives + else if (Directive.class.isAssignableFrom(loadedClass)) { + addonInfo.addDirective(loadedClass); + } + // wechatAddons + else if (WechatAddon.class.isAssignableFrom(loadedClass)) { + addonInfo.addWechatAddon(loadedClass); + } + // addonClass + else if (Addon.class.isAssignableFrom(loadedClass)) { + addonInfo.setAddonClass(loadedClass); + } + // upgraderClass + else if (AddonUpgrader.class.isAssignableFrom(loadedClass)) { + addonInfo.setUpgraderClass(loadedClass); + } + + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + } + } + + + private static Class[] default_excludes = new Class[]{JbootEventListener.class, JbootmqMessageListener.class, Serializable.class}; + + /** + * 初始化 @Bean 注解的映射关系 + */ + private void initBeanMapping(Class implClass) { + + Class[] interfaceClasses = implClass.getInterfaces(); + + if (interfaceClasses == null || interfaceClasses.length == 0) { + return; + } + + Class[] excludes = buildExcludeClasses(implClass); + + for (Class interfaceClass : interfaceClasses) { + if (inExcludes(interfaceClass, excludes) == false) { + AopManager.me().addMapping(interfaceClass, implClass); + } + } + } + + private Class[] buildExcludeClasses(Class implClass) { + BeanExclude beanExclude = (BeanExclude) implClass.getAnnotation(BeanExclude.class); + + //对某些系统的类 进行排除,例如:Serializable 等 + return beanExclude == null + ? default_excludes + : ArrayUtil.concat(default_excludes, beanExclude.value()); + } + + private boolean inExcludes(Class interfaceClass, Class[] excludes) { + for (Class ex : excludes) { + if (ex.isAssignableFrom(interfaceClass)) { + return true; + } + } + return false; + } + + static final List SUPPORT_NATIVE_SUFFIXES = Lists.newArrayList(".so", ".dylib", ".dll"); + + @Override + public InputStream getResourceAsStream(String name) { + InputStream superStream = super.getResourceAsStream(name); + int dotLastIndex = name.lastIndexOf("."); + if (dotLastIndex > -1) { + String suffix = name.substring(dotLastIndex); + boolean isSupport = SUPPORT_NATIVE_SUFFIXES.contains(suffix); + if (superStream == null && isSupport) { + try { + ZipEntry zipEntry = new ZipEntry(name); + return new JarFile(addonInfo.buildJarFile()).getInputStream(zipEntry); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + } + return superStream; + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/AddonInfo.java b/jpress-core/src/main/java/io/jpress/core/addon/AddonInfo.java index f26a4a9ca49383ade3dabef60cdccfe3bf57c916..ef11c75da0e7709c12486fe1e6ffff6d5e62c770 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/AddonInfo.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/AddonInfo.java @@ -1,350 +1,350 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon; - -import com.jfinal.aop.Aop; -import com.jfinal.aop.Interceptor; -import com.jfinal.core.Controller; -import com.jfinal.handler.Handler; -import com.jfinal.kit.PathKit; -import com.jfinal.plugin.activerecord.ActiveRecordPlugin; -import com.jfinal.template.Directive; -import io.jboot.db.annotation.Table; -import io.jboot.db.model.JbootModel; -import io.jboot.utils.StrUtil; -import io.jboot.web.directive.annotation.JFinalDirective; -import io.jpress.core.wechat.WechatAddon; -import io.jpress.core.wechat.WechatAddonConfig; - -import java.io.File; -import java.io.Serializable; -import java.util.*; - -public class AddonInfo implements Serializable { - - public static final int STATUS_INIT = 0; - public static final int STATUS_INSTALL = 1; - public static final int STATUS_START = 2; - - private String id; - private String title; - private String description; - private String author; - private String authorWebsite; - private String version; - private int versionCode; - - private Class addonClass; - private Class upgraderClass; - private int status = STATUS_INIT; - - private List> controllers; - private List> interceptors; - private List> handlers; - private List> models; - private List> directives; - private List> wechatAddons; - - private ActiveRecordPlugin arp; - private Map config; - - private String readmeText; - private String changeLogText; - - public AddonInfo() { - - } - - public AddonInfo(Properties properties) { - this.id = properties.getProperty("id"); - this.title = properties.getProperty("title"); - this.description = properties.getProperty("description"); - this.author = properties.getProperty("author"); - this.authorWebsite = properties.getProperty("authorWebsite"); - this.version = StrUtil.obtainDefaultIfBlank(properties.getProperty("version"), "v1.0.0"); - this.versionCode = Integer.valueOf(properties.getProperty("versionCode", "1")); - } - - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public Class getAddonClass() { - return addonClass; - } - - public void setAddonClass(Class addonClass) { - this.addonClass = addonClass; - } - - public Class getUpgraderClass() { - return upgraderClass; - } - - public void setUpgraderClass(Class upgraderClass) { - this.upgraderClass = upgraderClass; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public String getAuthorWebsite() { - return authorWebsite; - } - - public void setAuthorWebsite(String authorWebsite) { - this.authorWebsite = authorWebsite; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public int getVersionCode() { - return versionCode; - } - - public void setVersionCode(int versionCode) { - this.versionCode = versionCode; - } - - public int getStatus() { - return status; - } - - public void setStatus(int status) { - this.status = status; - } - - public Map getConfig() { - return config; - } - - public void setConfig(Map config) { - this.config = config; - } - - public AddonInfo addConfig(String key, String value) { - if (this.config == null) { - this.config = new HashMap<>(); - } - - this.config.put(key, value); - return this; - } - - public boolean isInstall() { - return status > STATUS_INIT; - } - - public boolean isStarted() { - return status > STATUS_INSTALL; - } - - public void addController(Class clazz) { - if (controllers == null) { - controllers = new ArrayList<>(); - } - controllers.add(clazz); - } - - public List> getControllers() { - return controllers; - } - - public void setControllers(List> controllers) { - this.controllers = controllers; - } - - - public void addInterceptor(Class clazz) { - if (interceptors == null) { - interceptors = new ArrayList<>(); - } - interceptors.add(clazz); - } - - public List> getInterceptors() { - return interceptors; - } - - public void setInterceptors(List> interceptors) { - this.interceptors = interceptors; - } - - public void addHandler(Class clazz) { - if (handlers == null) { - handlers = new ArrayList<>(); - } - handlers.add(clazz); - } - - public List> getHandlers() { - return handlers; - } - - public void setHandlers(List> handlers) { - this.handlers = handlers; - } - - - public void addModel(Class clazz) { - Table table = clazz.getAnnotation(Table.class); - if (table == null) { - return; - } - if (models == null) { - models = new ArrayList<>(); - } - models.add(clazz); - } - - public List> getModels() { - return models; - } - - public void setModels(List> models) { - this.models = models; - } - - - public void addDirective(Class clazz) { - JFinalDirective directive = clazz.getAnnotation(JFinalDirective.class); - if (directive == null) { - return; - } - if (directives == null) { - directives = new ArrayList<>(); - } - directives.add(clazz); - } - - public List> getDirectives() { - return directives; - } - - public void setDirectives(List> directives) { - this.directives = directives; - } - - public void addWechatAddon(Class clazz) { - WechatAddonConfig directive = clazz.getAnnotation(WechatAddonConfig.class); - if (directive == null) { - return; - } - if (wechatAddons == null) { - wechatAddons = new ArrayList<>(); - } - wechatAddons.add(clazz); - } - - - public List> getWechatAddons() { - return wechatAddons; - } - - public void setWechatAddons(List> wechatAddons) { - this.wechatAddons = wechatAddons; - } - - public ActiveRecordPlugin getArp() { - return arp; - } - - public ActiveRecordPlugin getOrCreateArp() { - if (arp == null) { - arp = AddonUtil.createRecordPlugin(this); - } - return arp; - } - - public void setArp(ActiveRecordPlugin arp) { - this.arp = arp; - } - - - public String getReadmeText() { - return readmeText; - } - - public void setReadmeText(String readmeText) { - this.readmeText = readmeText; - } - - public String getChangeLogText() { - return changeLogText; - } - - public void setChangeLogText(String changeLogText) { - this.changeLogText = changeLogText; - } - - public File buildJarFile() { - - String webRoot = PathKit.getWebRootPath(); - - StringBuilder fileName = new StringBuilder(webRoot); - fileName.append(File.separator); - fileName.append("WEB-INF"); - fileName.append(File.separator); - fileName.append("addons"); - fileName.append(File.separator); - fileName.append(getId()); - fileName.append(".jar"); - - return new File(fileName.toString()); - } - - public Addon getAddon() { - return addonClass == null ? null : Aop.get(addonClass); - } - - public AddonUpgrader getAddonUpgrader() { - return upgraderClass == null ? null : Aop.get(upgraderClass); - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon; + +import com.jfinal.aop.Aop; +import com.jfinal.aop.Interceptor; +import com.jfinal.core.Controller; +import com.jfinal.handler.Handler; +import com.jfinal.kit.PathKit; +import com.jfinal.plugin.activerecord.ActiveRecordPlugin; +import com.jfinal.template.Directive; +import io.jboot.db.annotation.Table; +import io.jboot.db.model.JbootModel; +import io.jboot.utils.StrUtil; +import io.jboot.web.directive.annotation.JFinalDirective; +import io.jpress.core.wechat.WechatAddon; +import io.jpress.core.wechat.WechatAddonConfig; + +import java.io.File; +import java.io.Serializable; +import java.util.*; + +public class AddonInfo implements Serializable { + + public static final int STATUS_INIT = 0; + public static final int STATUS_INSTALL = 1; + public static final int STATUS_START = 2; + + private String id; + private String title; + private String description; + private String author; + private String authorWebsite; + private String version; + private int versionCode; + + private Class addonClass; + private Class upgraderClass; + private int status = STATUS_INIT; + + private List> controllers; + private List> interceptors; + private List> handlers; + private List> models; + private List> directives; + private List> wechatAddons; + + private ActiveRecordPlugin arp; + private Map config; + + private String readmeText; + private String changeLogText; + + public AddonInfo() { + + } + + public AddonInfo(Properties properties) { + this.id = properties.getProperty("id"); + this.title = properties.getProperty("title"); + this.description = properties.getProperty("description"); + this.author = properties.getProperty("author"); + this.authorWebsite = properties.getProperty("authorWebsite"); + this.version = StrUtil.obtainDefaultIfBlank(properties.getProperty("version"), "v1.0.0"); + this.versionCode = Integer.valueOf(properties.getProperty("versionCode", "1")); + } + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Class getAddonClass() { + return addonClass; + } + + public void setAddonClass(Class addonClass) { + this.addonClass = addonClass; + } + + public Class getUpgraderClass() { + return upgraderClass; + } + + public void setUpgraderClass(Class upgraderClass) { + this.upgraderClass = upgraderClass; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAuthorWebsite() { + return authorWebsite; + } + + public void setAuthorWebsite(String authorWebsite) { + this.authorWebsite = authorWebsite; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public int getVersionCode() { + return versionCode; + } + + public void setVersionCode(int versionCode) { + this.versionCode = versionCode; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public Map getConfig() { + return config; + } + + public void setConfig(Map config) { + this.config = config; + } + + public AddonInfo addConfig(String key, String value) { + if (this.config == null) { + this.config = new HashMap<>(); + } + + this.config.put(key, value); + return this; + } + + public boolean isInstall() { + return status > STATUS_INIT; + } + + public boolean isStarted() { + return status > STATUS_INSTALL; + } + + public void addController(Class clazz) { + if (controllers == null) { + controllers = new ArrayList<>(); + } + controllers.add(clazz); + } + + public List> getControllers() { + return controllers; + } + + public void setControllers(List> controllers) { + this.controllers = controllers; + } + + + public void addInterceptor(Class clazz) { + if (interceptors == null) { + interceptors = new ArrayList<>(); + } + interceptors.add(clazz); + } + + public List> getInterceptors() { + return interceptors; + } + + public void setInterceptors(List> interceptors) { + this.interceptors = interceptors; + } + + public void addHandler(Class clazz) { + if (handlers == null) { + handlers = new ArrayList<>(); + } + handlers.add(clazz); + } + + public List> getHandlers() { + return handlers; + } + + public void setHandlers(List> handlers) { + this.handlers = handlers; + } + + + public void addModel(Class clazz) { + Table table = clazz.getAnnotation(Table.class); + if (table == null) { + return; + } + if (models == null) { + models = new ArrayList<>(); + } + models.add(clazz); + } + + public List> getModels() { + return models; + } + + public void setModels(List> models) { + this.models = models; + } + + + public void addDirective(Class clazz) { + JFinalDirective directive = clazz.getAnnotation(JFinalDirective.class); + if (directive == null) { + return; + } + if (directives == null) { + directives = new ArrayList<>(); + } + directives.add(clazz); + } + + public List> getDirectives() { + return directives; + } + + public void setDirectives(List> directives) { + this.directives = directives; + } + + public void addWechatAddon(Class clazz) { + WechatAddonConfig directive = clazz.getAnnotation(WechatAddonConfig.class); + if (directive == null) { + return; + } + if (wechatAddons == null) { + wechatAddons = new ArrayList<>(); + } + wechatAddons.add(clazz); + } + + + public List> getWechatAddons() { + return wechatAddons; + } + + public void setWechatAddons(List> wechatAddons) { + this.wechatAddons = wechatAddons; + } + + public ActiveRecordPlugin getArp() { + return arp; + } + + public ActiveRecordPlugin getOrCreateArp() { + if (arp == null) { + arp = AddonUtil.createRecordPlugin(this); + } + return arp; + } + + public void setArp(ActiveRecordPlugin arp) { + this.arp = arp; + } + + + public String getReadmeText() { + return readmeText; + } + + public void setReadmeText(String readmeText) { + this.readmeText = readmeText; + } + + public String getChangeLogText() { + return changeLogText; + } + + public void setChangeLogText(String changeLogText) { + this.changeLogText = changeLogText; + } + + public File buildJarFile() { + + String webRoot = PathKit.getWebRootPath(); + + StringBuilder fileName = new StringBuilder(webRoot); + fileName.append(File.separator); + fileName.append("WEB-INF"); + fileName.append(File.separator); + fileName.append("addons"); + fileName.append(File.separator); + fileName.append(getId()); + fileName.append(".jar"); + + return new File(fileName.toString()); + } + + public Addon getAddon() { + return addonClass == null ? null : Aop.get(addonClass); + } + + public AddonUpgrader getAddonUpgrader() { + return upgraderClass == null ? null : Aop.get(upgraderClass); + } + + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/AddonManager.java b/jpress-core/src/main/java/io/jpress/core/addon/AddonManager.java index a63677beeae093845dddb74a84fb6e7243b3e683..cd88ef29afacf40f331807748a48a8bd95f43d7b 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/AddonManager.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/AddonManager.java @@ -1,1024 +1,1024 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon; - -import com.jfinal.aop.Aop; -import com.jfinal.aop.Interceptor; -import com.jfinal.core.Controller; -import com.jfinal.handler.Handler; -import com.jfinal.kit.LogKit; -import com.jfinal.kit.PathKit; -import com.jfinal.kit.Ret; -import com.jfinal.log.Log; -import com.jfinal.plugin.activerecord.ActiveRecordPlugin; -import com.jfinal.plugin.activerecord.Model; -import com.jfinal.plugin.activerecord.TableMapping; -import com.jfinal.render.RenderManager; -import com.jfinal.template.Directive; -import com.jfinal.template.expr.ast.FieldKit; -import com.jfinal.template.expr.ast.MethodKit; -import io.jboot.Jboot; -import io.jboot.components.event.JbootEvent; -import io.jboot.components.event.JbootEventListener; -import io.jboot.db.annotation.Table; -import io.jboot.db.model.JbootModel; -import io.jboot.db.model.JbootModelConfig; -import io.jboot.utils.AnnotationUtil; -import io.jboot.utils.FileUtil; -import io.jboot.utils.StrUtil; -import io.jboot.web.directive.annotation.JFinalDirective; -import io.jpress.core.addon.controller.AddonControllerManager; -import io.jpress.core.addon.handler.AddonHandlerManager; -import io.jpress.core.addon.interceptor.AddonInterceptorManager; -import io.jpress.core.install.Installer; -import io.jpress.core.template.TemplateManager; -import io.jpress.core.wechat.WechatAddon; -import io.jpress.core.wechat.WechatAddonConfig; -import io.jpress.core.wechat.WechatAddonInfo; -import io.jpress.core.wechat.WechatAddonManager; -import io.jpress.service.OptionService; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 插件管理器:安装、卸载、启用、停用 - *

    - * 安装的动作: - * 1、解压jar资源文件 - * 2、解压成功后,回调插件的 onInstall() - * 3、回调成功后,标识该插件已经安装 - *

    - * 卸载的动作: - * 1、回调插件的 onUninstall() - * 2、回调成功后删除jar文件以及资源文件 - * 3、删除安装、启动、停止等标识 - *

    - * 启用插件: - * 1、标识插件启用 - * 2、添加插件的 controller、handler、interceptor 到对应的管理器 - * 3、回调插件的 onStart() - * 4、每次重启 JPress 都会调用 onStart() - *

    - * 停用插件: - * 1、删除插件的 controller、handler、interceptor - * 2、删除插件启用标识 - * 3、回调插件的 onStop() - *

    - *

    - * 插件开发: - * 1、插件的作者可以在 onInstall() 进行数据库表创建等工作 - * 2、插件的作者可以在 onUninstall() 进行数据库表删除和其他资源删除等工作 - */ -public class AddonManager implements JbootEventListener { - - private static final Log LOG = Log.getLog(AddonManager.class); - - private static final String ADDON_INSTALL_PREFFIX = "addon-install:"; - private static final String ADDON_START_PREFFIX = "addon-start:"; - - private static final AddonManager me = new AddonManager(); - - public static AddonManager me() { - return me; - } - - private Map addonsMap = new ConcurrentHashMap<>(); - private AddonNotifier notifier; - - public void init() { - - if (Installer.notInstall()) { - Installer.addListener(this); - return; - } - - doInitAddons(); - } - - /** - * 启动的时候,加载所有插件 - * 备注:插件可能是复制到插件目录下,而非通过后台进行 "安装" - */ - private void doInitAddons() { - - File addonDir = new File(PathKit.getWebRootPath(), "WEB-INF/addons"); - if (!addonDir.exists()) { - return; - } - - File[] addonJarFiles = addonDir.listFiles((dir, name) -> name.endsWith(".jar")); - if (addonJarFiles == null || addonJarFiles.length == 0) { - return; - } - - initAddonsMap(addonJarFiles); - doInstallAddonsInApplicationStarted(); - doStartAddonInApplicationStarted(); - - } - - - private void initAddonsMap(File[] addonJarFiles) { - for (File jarFile : addonJarFiles) { - AddonInfo addonInfo = AddonUtil.readAddonInfo(jarFile); - if (addonInfo != null && StrUtil.isNotBlank(addonInfo.getId())) { - addonsMap.put(addonInfo.getId(), addonInfo); - } - } - } - - - private void doInstallAddonsInApplicationStarted() { - - OptionService optionService = Aop.get(OptionService.class); - for (AddonInfo addonInfo : addonsMap.values()) { - if (optionService.findByKey(ADDON_INSTALL_PREFFIX + addonInfo.getId()) != null) { - addonInfo.setStatus(AddonInfo.STATUS_INSTALL); - } - } - } - - private void doStartAddonInApplicationStarted() { - OptionService optionService = Aop.get(OptionService.class); - for (AddonInfo addonInfo : addonsMap.values()) { - if (optionService.findByKey(ADDON_START_PREFFIX + addonInfo.getId()) != null - && addonInfo.isInstall() - && !addonInfo.isStarted() - ) { - try { - doStart(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - stop(addonInfo); - } - } - } - } - - public AddonInfo getAddonInfo(String id) { - if (StrUtil.isBlank(id)) { - return null; - } - return addonsMap.get(id); - } - - public List getAllAddonInfos() { - return new ArrayList<>(addonsMap.values()); - } - - - public boolean install(String id) { - return install(getAddonInfo(id).buildJarFile()); - } - - /** - * 安装插件: - * 1、解压jar资源文件 - * 2、解压成功后,回调插件的 onInstall() - * 3、回调成功后,标识该插件已经安装 - * - * @param jarFile - * @return - */ - - public boolean install(File jarFile) { - try { - AddonInfo addonInfo = AddonUtil.readAddonInfo(jarFile); - addonsMap.put(addonInfo.getId(), addonInfo); - Addon addon = addonInfo.getAddon(); - - AddonUtil.unzipResources(addonInfo); - - if (addon != null) { - addon.onInstall(addonInfo); - } - - addonInfo.setStatus(AddonInfo.STATUS_INSTALL); - OptionService optionService = Aop.get(OptionService.class); - - if (optionService.saveOrUpdate(ADDON_INSTALL_PREFFIX + addonInfo.getId(), "true") != null) { - notifyAddonInstall(FileUtil.removeRootPath(jarFile.getAbsolutePath())); - } - - return true; - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - return false; - - } - - - public boolean uninstall(String id) { - return uninstall(id, true); - } - - public boolean uninstall(String id, boolean withNotify) { - try { - return uninstall(getAddonInfo(id)); - } finally { - if (withNotify) { - notifyAddonUninstall(id); - } - } - } - - /** - * 卸载的动作: - * 1、回调插件的 onUninstall() - * 2、回调成功后删除jar文件以及资源文件 - * 3、删除安装、启动、停止等标识 - * - * @param addonInfo - * @return - */ - public boolean uninstall(AddonInfo addonInfo) { - if (addonInfo == null) { - return false; - } - - //执行插件的 uninstall 方法 - try { - invokeAddonUnisntallMethod(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //卸载插件可能自带的 本地库 - try { - unloadNativeLibs(addonInfo.getAddon()); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //删除所有插件文件 - try { - clearAddonFiles(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //删除插件对应的数据库记录 - try { - deleteDbRecord(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //清除插件的缓存信息 - try { - clearAddonCache(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - return true; - } - - private void deleteDbRecord(AddonInfo addonInfo) { - OptionService optionService = Aop.get(OptionService.class); - optionService.deleteByKey(ADDON_INSTALL_PREFFIX + addonInfo.getId()); - } - - private void clearAddonFiles(AddonInfo addonInfo) { - FileUtils.deleteQuietly(new File(PathKit.getWebRootPath(), "addons/" + addonInfo.getId())); - AddonUtil.forceDelete(addonInfo.buildJarFile()); - } - - private void invokeAddonUnisntallMethod(AddonInfo addonInfo) { - Addon addon = addonInfo.getAddon(); - if (addon != null) { - addon.onUninstall(addonInfo); - } - } - - /** - * 卸载插件中的native library - * - * @param addon - */ - private synchronized void unloadNativeLibs(Addon addon) { - if (addon == null) { - return; - } - try { - ClassLoader classLoader = addon.getClass().getClassLoader(); - Field field = ClassLoader.class.getDeclaredField("nativeLibraries"); - field.setAccessible(true); - Vector libs = (Vector) field.get(classLoader); - Iterator it = libs.iterator(); - Object o; - while (it.hasNext()) { - o = it.next(); - Method finalize = o.getClass().getDeclaredMethod("finalize", new Class[0]); - finalize.setAccessible(true); - finalize.invoke(o, new Object[0]); - it.remove(); - libs.remove(o); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void clearAddonCache(AddonInfo addonInfo) { - AddonUtil.clearAddonInfoCache(addonInfo.buildJarFile()); - addonInfo.setStatus(AddonInfo.STATUS_INIT); - addonsMap.remove(addonInfo.getId()); - } - - - public boolean start(String addonInfoId) { - return start(addonInfoId, true); - } - - - public boolean start(String addonInfoId, boolean withNotify) { - return start(getAddonInfo(addonInfoId), withNotify); - } - - /** - * 启动的动作: - * 1、标识插件启用 - * 2、添加插件的 controller、handler、interceptor 到对应的管理器 - * 3、若有 Model 类,启动新的 arp 插件 - * 4、回调插件的 onStart() - * 5、构建后台或用户中心菜单 - *

    - * 备注: - * 每次重启 JPress 都会调用 onStart() - * - * @param addonInfo - * @return - */ - public boolean start(AddonInfo addonInfo, boolean withNotify) { - try { - doStart(addonInfo); - if (withNotify) { - notifyAddonStarted(addonInfo.getId()); - } - return true; - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - stop(addonInfo.getId(), withNotify); - } - return false; - } - - private void doStart(AddonInfo addonInfo) { - - //添加插件的 Controllers - addControllers(addonInfo); - - //添加插件的 Handlers - addHandlers(addonInfo); - - //添加插件的 指令 - addDirectives(addonInfo); - - //添加插件的拦截器 - addInterceptors(addonInfo); - - //添加微信消息插件 - addWechatAddons(addonInfo); - - //启动插件的数据库连接插件 - startActiveRecordPlugin(addonInfo); - - //执行插件 onStart() 方法 - invokeStartMethod(addonInfo); - - //构建 JPress 应用的 url 映射 - buildApplicationActionMapping(); - - //设置插件的启动标识(状态) - setAddonStartedFalg(addonInfo); - - } - - - private void setAddonStartedFalg(AddonInfo addonInfo) { - addonInfo.setStatus(AddonInfo.STATUS_START); - OptionService optionService = Aop.get(OptionService.class); - optionService.saveOrUpdate(ADDON_START_PREFFIX + addonInfo.getId(), "true"); - - } - - private void buildApplicationActionMapping() { - AddonControllerManager.buildActionMapping(); - } - - private void invokeStartMethod(AddonInfo addonInfo) { - Addon addon = addonInfo.getAddon(); - if (addon != null) { - addon.onStart(addonInfo); - } - } - - private void startActiveRecordPlugin(AddonInfo addonInfo) { - List> modelClasses = addonInfo.getModels(); - if (modelClasses != null && !modelClasses.isEmpty()) { - - ActiveRecordPlugin arp = addonInfo.getOrCreateArp(); - - List tableList = getTableList(arp); - - for (Class c : modelClasses) { - - Table tableAnnotation = c.getAnnotation(Table.class); - boolean needAddMapping = true; - - if (tableList != null && !tableList.isEmpty()) { - for (com.jfinal.plugin.activerecord.Table t : tableList) { - if (t.getName().equals(AnnotationUtil.get(tableAnnotation.tableName()))) { - needAddMapping = false; - break; - } - } - } - - if (needAddMapping) { - if (StrUtil.isNotBlank(tableAnnotation.primaryKey())) { - arp.addMapping(AnnotationUtil.get(tableAnnotation.tableName()), AnnotationUtil.get(tableAnnotation.primaryKey()), (Class>) c); - } else { - arp.addMapping(AnnotationUtil.get(tableAnnotation.tableName()), (Class>) c); - } - } - } - addonInfo.setArp(arp); - arp.start(); - } - } - - private void addWechatAddons(AddonInfo addonInfo) { - List> wechatAddons = addonInfo.getWechatAddons(); - if (wechatAddons != null) { - for (Class c : wechatAddons) { - WechatAddonConfig config = c.getAnnotation(WechatAddonConfig.class); - WechatAddonInfo wechatAddon = new WechatAddonInfo(config, c); - WechatAddonManager.me().addWechatAddon(wechatAddon); - WechatAddonManager.me().doEnableAddon(config.id()); - } - } - } - - private void addInterceptors(AddonInfo addonInfo) { - List> interceptorClasses = addonInfo.getInterceptors(); - if (interceptorClasses != null) { - for (Class c : interceptorClasses) { - AddonInterceptorManager.addInterceptor(c); - } - } - } - - private void addDirectives(AddonInfo addonInfo) { - List> directives = addonInfo.getDirectives(); - if (directives != null) { - for (Class c : directives) { - JFinalDirective ann = c.getAnnotation(JFinalDirective.class); - String directiveName = AnnotationUtil.get(ann.value()); - // 先移除,后添加,若有相同指令的情况下, - // 后安装的插件会替换掉已经存在的指令 - RenderManager.me().getEngine().removeDirective(directiveName); - RenderManager.me().getEngine().addDirective(directiveName, c); - } - } - } - - private void addHandlers(AddonInfo addonInfo) { - List> handlerClasses = addonInfo.getHandlers(); - if (handlerClasses != null) { - for (Class c : handlerClasses) { - AddonHandlerManager.addHandler(c); - } - } - } - - private void addControllers(AddonInfo addonInfo) { - List> controllerClasses = addonInfo.getControllers(); - if (controllerClasses != null) { - for (Class c : controllerClasses) { - AddonControllerManager.addController(c, addonInfo.getId()); - } - } - } - - - public boolean stop(String id) { - return stop(id, true); - } - - public boolean stop(String id, boolean withNotify) { - try { - return stop(getAddonInfo(id)); - } finally { - if (withNotify) { - notifyAddonStoped(id); - } - } - } - - - public boolean stop(AddonInfo addonInfo) { - if (addonInfo == null){ - return false; - } - - //删除插件的所有Controller - try { - deleteControllers(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //删除插件的所有handler - try { - deleteHandlers(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //删除插件的所有指令 - try { - deleteDirectives(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //删除插件的所有拦截器 - try { - deleteInteceptors(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //移除所有的微信插件 - try { - deleteWechatAddons(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //停止插件的数据库访问 - try { - stopActiveRecordPlugin(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //移除所有的table数据 - try { - removeModelsCache(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //移除插件的模板缓存 - try { - removeTemplateCache(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //调用插件的 stop() 方法 - try { - invokeAddonStopMethod(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //重建整个JPress应用的ActionMapping映射 - try { - rebuildApplicationActionMapping(); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - //清除插件的状态,防止被重用 - try { - deleteStartedFlag(addonInfo); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - return true; - } - - private void deleteStartedFlag(AddonInfo addonInfo) { - addonInfo.setStatus(AddonInfo.STATUS_INSTALL); - OptionService optionService = Aop.get(OptionService.class); - optionService.deleteByKey(ADDON_START_PREFFIX + addonInfo.getId()); - } - - private void rebuildApplicationActionMapping() { - AddonControllerManager.buildActionMapping(); - } - - private void invokeAddonStopMethod(AddonInfo addonInfo) { - Addon addon = addonInfo.getAddon(); - if (addon != null) { - addon.onStop(addonInfo); - } - } - - private void removeTemplateCache(AddonInfo addonInfo) { - // 清除模板引擎的 field 和 method 缓存 - // 否则可能会出现 object is not an instance of declaring class 的异常 - // https://gitee.com/fuhai/jpress/issues/IS5YQ - FieldKit.clearCache(); - MethodKit.clearCache(); - TemplateManager.me().clearCache(false); - } - - private void stopActiveRecordPlugin(AddonInfo addonInfo) throws Exception { - ActiveRecordPlugin arp = addonInfo.getArp(); - if (arp != null && arp.stop()) { - clearStopedTableMapping(arp); - } - } - - private void clearStopedTableMapping(ActiveRecordPlugin arp) throws Exception { - - List tables = getTableList(arp); - - if (tables == null || tables.isEmpty()) { - return; - } - - - Field modelToTableMapField = TableMapping.class.getDeclaredField("modelToTableMap"); - modelToTableMapField.setAccessible(true); - Map>, com.jfinal.plugin.activerecord.Table> modelToTableMap = - (Map>, com.jfinal.plugin.activerecord.Table>) modelToTableMapField.get(TableMapping.me()); - - if (modelToTableMap == null || modelToTableMap.isEmpty()) { - return; - } - - for (com.jfinal.plugin.activerecord.Table table : tables) { - modelToTableMap.remove(table.getModelClass()); - } - } - - private List getTableList(ActiveRecordPlugin arp) { - try { - Field tableListField = ActiveRecordPlugin.class.getDeclaredField("tableList"); - tableListField.setAccessible(true); - return (List) tableListField.get(arp); - } catch (Exception ex) { - LogKit.error(ex.toString(), ex); - } - return null; - } - - /** - * 必须要移除所有的缓存,否则当插件卸载重新安装的时候, - * 缓存里的可能还存在数据,由于可能是内存缓存,所有可能导致Class转化异常的问题 - * PS:每次新安装的插件,都是一个新的 Classloader - * - * @param addonInfo - */ - private void removeModelsCache(AddonInfo addonInfo) { - List> modelClasses = addonInfo.getModels(); - if (modelClasses != null) { - modelClasses.forEach(aClass -> { - Table table = aClass.getAnnotation(Table.class); - String tableName = AnnotationUtil.get(table.tableName()); - JbootModelConfig.getConfig().getIdCache().removeAll(tableName); - Jboot.getCache().removeAll(tableName); - }); - } - } - - private void deleteWechatAddons(AddonInfo addonInfo) { - List> wechatAddons = addonInfo.getWechatAddons(); - if (wechatAddons != null) { - for (Class c : wechatAddons) { - WechatAddonConfig config = c.getAnnotation(WechatAddonConfig.class); - WechatAddonManager.me().deleteWechatAddon(AnnotationUtil.get(config.id())); - } - } - } - - private void deleteInteceptors(AddonInfo addonInfo) { - List> interceptorClasses = addonInfo.getInterceptors(); - if (interceptorClasses != null) { - for (Class c : interceptorClasses) { - AddonInterceptorManager.deleteInterceptor(c); - } - } - } - - private void deleteDirectives(AddonInfo addonInfo) { - List> directives = addonInfo.getDirectives(); - if (directives != null) { - for (Class c : directives) { - JFinalDirective ann = c.getAnnotation(JFinalDirective.class); - RenderManager.me().getEngine().removeDirective(AnnotationUtil.get(ann.value())); - } - } - } - - private void deleteHandlers(AddonInfo addonInfo) { - List> handlerClasses = addonInfo.getHandlers(); - if (handlerClasses != null) { - for (Class c : handlerClasses) { - AddonHandlerManager.deleteHandler(c); - } - } - } - - private void deleteControllers(AddonInfo addonInfo) { - List> controllerClasses = addonInfo.getControllers(); - if (controllerClasses != null) { - for (Class c : controllerClasses) { - AddonControllerManager.deleteController(c); - } - } - } - - - public Ret upgrade(File newAddonFile, String oldAddonId) { - AddonInfo oldAddon = AddonManager.me().getAddonInfo(oldAddonId); - if (oldAddon == null) { - return failRet("升级失败:无法读取旧的插件信息,可能该插件不存在。"); - } - - AddonInfo addon = AddonUtil.readSimpleAddonInfo(newAddonFile); - if (addon == null || StrUtil.isBlank(addon.getId())) { - return failRet("升级失败:无法读取新插件配置文件。"); - } - - if (!addon.getId().equals(oldAddonId)) { - return failRet("升级失败:新插件的ID和旧插件不一致。"); - } - - if (addon.getVersionCode() <= oldAddon.getVersionCode()) { - return failRet("升级失败:新插件的版本号必须大于已安装插件的版本号。"); - } - - boolean upgradeSuccess = false; - try { - upgradeSuccess = doUpgrade(newAddonFile, addon, oldAddon); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - upgradeSuccess = false; - } finally { - if (!upgradeSuccess) { - doUpgradeRollback(addon, oldAddon); - } - } - - return upgradeSuccess ? Ret.ok() : failRet("插件升级失败,请联系管理员。"); - } - - /** - * 开始升级 - * - * @param newAddon - * @param oldAddon - */ - private boolean doUpgrade(File newAddonFile, AddonInfo newAddon, AddonInfo oldAddon) throws IOException { - - //对已经安装的插件进行备份 - doBackupOldAddon(oldAddon); - - //解压缩新的资源文件 - doUnzipNewAddon(newAddonFile, newAddon); - - //获得已经进行 classloader 加载的 addon - if (!doInvokeAddonUpgradeMethod(newAddon, oldAddon)) { - return false; - } - - //设置该插件的状态为已经安装的状态 - if (!doSetAddonStatus(newAddon.getId())) { - return false; - } - - return true; - } - - private boolean doSetAddonStatus(String id) { - - AddonInfo addonInfo = addonsMap.get(id); - addonInfo.setStatus(AddonInfo.STATUS_INSTALL); - - OptionService optionService = Aop.get(OptionService.class); - return optionService.saveOrUpdate(ADDON_INSTALL_PREFFIX + id, "true") != null; - } - - private boolean doInvokeAddonUpgradeMethod(AddonInfo newAddon, AddonInfo oldAddon) { - - AddonUtil.clearAddonInfoCache(newAddon.buildJarFile()); - AddonInfo addon = AddonUtil.readAddonInfo(newAddon.buildJarFile()); - AddonUpgrader upgrader = addon.getAddonUpgrader(); - if (upgrader != null) { - boolean success = false; - try { - success = upgrader.onUpgrade(oldAddon, addon); - } finally { - if (!success) { - upgrader.onRollback(oldAddon, addon); - return false; - } - } - } - - - addonsMap.put(addon.getId(), addon); - return true; - } - - private void doUnzipNewAddon(File newAddonFile, AddonInfo newAddon) throws IOException { - File destAddonFile = newAddon.buildJarFile(); - FileUtils.moveFile(newAddonFile, destAddonFile); - - AddonUtil.unzipResources(newAddon); - } - - private void doBackupOldAddon(AddonInfo oldAddon) throws IOException { - - //备份 资源文件 - String resPath = PathKit.getWebRootPath() - + File.separator - + "addons" - + File.separator - + oldAddon.getId(); - - String resBakPath = resPath + "_bak"; - - //清空之前的备份文件 - File resBakPathDir = new File(resBakPath); - if (resBakPathDir.exists()) { - FileUtils.deleteDirectory(resBakPathDir); - } - - //备份资源文件 - FileUtils.moveDirectory(new File(resPath), resBakPathDir); - - File jarFile = oldAddon.buildJarFile(); - - File bakJarFile = new File(jarFile.getAbsolutePath() + "_bak"); - if (bakJarFile.exists()) { - FileUtils.deleteQuietly(bakJarFile); - } - - //备份jar文件 - FileUtils.moveFile(jarFile, bakJarFile); - } - - /** - * 升级回滚 - * - * @param addon - * @param oldAddon - */ - private void doUpgradeRollback(AddonInfo addon, AddonInfo oldAddon) { - - //删除刚刚升级安装的插件信息 - try { - doDeleteNewAddon(addon); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - - //恢复已经备份的插件信息 - try { - doRollBackBackups(addon); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - - //重置插件信息 - try { - doRestAddonInfo(oldAddon); - doSetAddonStatus(oldAddon.getId()); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - - } - - private void doRestAddonInfo(AddonInfo addonInfo) { - AddonUtil.clearAddonInfoCache(addonInfo.buildJarFile()); - AddonInfo addon = AddonUtil.readAddonInfo(addonInfo.buildJarFile()); - addonsMap.put(addon.getId(), addon); - } - - private void doRollBackBackups(AddonInfo addon) { - //备份 资源文件 - String resPath = PathKit.getWebRootPath() - + File.separator - + "addons" - + File.separator - + addon.getId(); - - String resBakPath = resPath + "_bak"; - - //恢复备份的资源文件 - try { - FileUtils.moveDirectory(new File(resBakPath), new File(resPath)); - } catch (IOException e) { - LOG.error(e.toString(), e); - } - - //恢复备份的jar文件 - try { - File bakJarFile = new File(addon.buildJarFile() + "_bak"); - FileUtils.moveFile(bakJarFile, addon.buildJarFile()); - } catch (IOException e) { - LOG.error(e.toString(), e); - } - - } - - private void doDeleteNewAddon(AddonInfo addon) { - AddonUtil.clearAddonInfoCache(addon.buildJarFile()); - - //删除已解压缩的资源文件 - FileUtils.deleteQuietly(new File(PathKit.getWebRootPath(), "addons/" + addon.getId())); - - //删除jar包 - AddonUtil.forceDelete(addon.buildJarFile()); - - //删除插件列表缓存 - addonsMap.remove(addon.getId()); - } - - private Ret failRet(String msg) { - return Ret.fail() - .set("success", false) - .setIfNotBlank("message", msg); - } - - //JbootEventListener.onEvent - @Override - public void onEvent(JbootEvent jbootEvent) { - init(); - } - - - private void notifyAddonInstall(String path) { - if (notifier != null){ - notifier.notifyAddonInstall(path); - } - } - - - private void notifyAddonStarted(String addonId) { - if (notifier != null){ - notifier.notifyAddonStarted(addonId); - } - } - - - private void notifyAddonStoped(String addonId) { - if (notifier != null){ - notifier.notifyAddonStoped(addonId); - } - } - - - private void notifyAddonUninstall(String addonId) { - if (notifier != null){ - notifier.notifyAddonUninstall(addonId); - } - } - - - public AddonNotifier getNotifier() { - return notifier; - } - - public void setNotifier(AddonNotifier notifier) { - this.notifier = notifier; - } - - public Map getAddonsMap() { - return addonsMap; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon; + +import com.jfinal.aop.Aop; +import com.jfinal.aop.Interceptor; +import com.jfinal.core.Controller; +import com.jfinal.handler.Handler; +import com.jfinal.kit.LogKit; +import com.jfinal.kit.PathKit; +import com.jfinal.kit.Ret; +import com.jfinal.log.Log; +import com.jfinal.plugin.activerecord.ActiveRecordPlugin; +import com.jfinal.plugin.activerecord.Model; +import com.jfinal.plugin.activerecord.TableMapping; +import com.jfinal.render.RenderManager; +import com.jfinal.template.Directive; +import com.jfinal.template.expr.ast.FieldKit; +import com.jfinal.template.expr.ast.MethodKit; +import io.jboot.Jboot; +import io.jboot.components.event.JbootEvent; +import io.jboot.components.event.JbootEventListener; +import io.jboot.db.annotation.Table; +import io.jboot.db.model.JbootModel; +import io.jboot.db.model.JbootModelConfig; +import io.jboot.utils.AnnotationUtil; +import io.jboot.utils.FileUtil; +import io.jboot.utils.StrUtil; +import io.jboot.web.directive.annotation.JFinalDirective; +import io.jpress.core.addon.controller.AddonControllerManager; +import io.jpress.core.addon.handler.AddonHandlerManager; +import io.jpress.core.addon.interceptor.AddonInterceptorManager; +import io.jpress.core.install.Installer; +import io.jpress.core.template.TemplateManager; +import io.jpress.core.wechat.WechatAddon; +import io.jpress.core.wechat.WechatAddonConfig; +import io.jpress.core.wechat.WechatAddonInfo; +import io.jpress.core.wechat.WechatAddonManager; +import io.jpress.service.OptionService; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 插件管理器:安装、卸载、启用、停用 + *

    + * 安装的动作: + * 1、解压jar资源文件 + * 2、解压成功后,回调插件的 onInstall() + * 3、回调成功后,标识该插件已经安装 + *

    + * 卸载的动作: + * 1、回调插件的 onUninstall() + * 2、回调成功后删除jar文件以及资源文件 + * 3、删除安装、启动、停止等标识 + *

    + * 启用插件: + * 1、标识插件启用 + * 2、添加插件的 controller、handler、interceptor 到对应的管理器 + * 3、回调插件的 onStart() + * 4、每次重启 JPress 都会调用 onStart() + *

    + * 停用插件: + * 1、删除插件的 controller、handler、interceptor + * 2、删除插件启用标识 + * 3、回调插件的 onStop() + *

    + *

    + * 插件开发: + * 1、插件的作者可以在 onInstall() 进行数据库表创建等工作 + * 2、插件的作者可以在 onUninstall() 进行数据库表删除和其他资源删除等工作 + */ +public class AddonManager implements JbootEventListener { + + private static final Log LOG = Log.getLog(AddonManager.class); + + private static final String ADDON_INSTALL_PREFFIX = "addon-install:"; + private static final String ADDON_START_PREFFIX = "addon-start:"; + + private static final AddonManager me = new AddonManager(); + + public static AddonManager me() { + return me; + } + + private Map addonsMap = new ConcurrentHashMap<>(); + private AddonNotifier notifier; + + public void init() { + + if (Installer.notInstall()) { + Installer.addListener(this); + return; + } + + doInitAddons(); + } + + /** + * 启动的时候,加载所有插件 + * 备注:插件可能是复制到插件目录下,而非通过后台进行 "安装" + */ + private void doInitAddons() { + + File addonDir = new File(PathKit.getWebRootPath(), "WEB-INF/addons"); + if (!addonDir.exists()) { + return; + } + + File[] addonJarFiles = addonDir.listFiles((dir, name) -> name.endsWith(".jar")); + if (addonJarFiles == null || addonJarFiles.length == 0) { + return; + } + + initAddonsMap(addonJarFiles); + doInstallAddonsInApplicationStarted(); + doStartAddonInApplicationStarted(); + + } + + + private void initAddonsMap(File[] addonJarFiles) { + for (File jarFile : addonJarFiles) { + AddonInfo addonInfo = AddonUtil.readAddonInfo(jarFile); + if (addonInfo != null && StrUtil.isNotBlank(addonInfo.getId())) { + addonsMap.put(addonInfo.getId(), addonInfo); + } + } + } + + + private void doInstallAddonsInApplicationStarted() { + + OptionService optionService = Aop.get(OptionService.class); + for (AddonInfo addonInfo : addonsMap.values()) { + if (optionService.findByKey(ADDON_INSTALL_PREFFIX + addonInfo.getId()) != null) { + addonInfo.setStatus(AddonInfo.STATUS_INSTALL); + } + } + } + + private void doStartAddonInApplicationStarted() { + OptionService optionService = Aop.get(OptionService.class); + for (AddonInfo addonInfo : addonsMap.values()) { + if (optionService.findByKey(ADDON_START_PREFFIX + addonInfo.getId()) != null + && addonInfo.isInstall() + && !addonInfo.isStarted() + ) { + try { + doStart(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + stop(addonInfo); + } + } + } + } + + public AddonInfo getAddonInfo(String id) { + if (StrUtil.isBlank(id)) { + return null; + } + return addonsMap.get(id); + } + + public List getAllAddonInfos() { + return new ArrayList<>(addonsMap.values()); + } + + + public boolean install(String id) { + return install(getAddonInfo(id).buildJarFile()); + } + + /** + * 安装插件: + * 1、解压jar资源文件 + * 2、解压成功后,回调插件的 onInstall() + * 3、回调成功后,标识该插件已经安装 + * + * @param jarFile + * @return + */ + + public boolean install(File jarFile) { + try { + AddonInfo addonInfo = AddonUtil.readAddonInfo(jarFile); + addonsMap.put(addonInfo.getId(), addonInfo); + Addon addon = addonInfo.getAddon(); + + AddonUtil.unzipResources(addonInfo); + + if (addon != null) { + addon.onInstall(addonInfo); + } + + addonInfo.setStatus(AddonInfo.STATUS_INSTALL); + OptionService optionService = Aop.get(OptionService.class); + + if (optionService.saveOrUpdate(ADDON_INSTALL_PREFFIX + addonInfo.getId(), "true") != null) { + notifyAddonInstall(FileUtil.removeRootPath(jarFile.getAbsolutePath())); + } + + return true; + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + return false; + + } + + + public boolean uninstall(String id) { + return uninstall(id, true); + } + + public boolean uninstall(String id, boolean withNotify) { + try { + return uninstall(getAddonInfo(id)); + } finally { + if (withNotify) { + notifyAddonUninstall(id); + } + } + } + + /** + * 卸载的动作: + * 1、回调插件的 onUninstall() + * 2、回调成功后删除jar文件以及资源文件 + * 3、删除安装、启动、停止等标识 + * + * @param addonInfo + * @return + */ + public boolean uninstall(AddonInfo addonInfo) { + if (addonInfo == null) { + return false; + } + + //执行插件的 uninstall 方法 + try { + invokeAddonUnisntallMethod(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //卸载插件可能自带的 本地库 + try { + unloadNativeLibs(addonInfo.getAddon()); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //删除所有插件文件 + try { + clearAddonFiles(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //删除插件对应的数据库记录 + try { + deleteDbRecord(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //清除插件的缓存信息 + try { + clearAddonCache(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + return true; + } + + private void deleteDbRecord(AddonInfo addonInfo) { + OptionService optionService = Aop.get(OptionService.class); + optionService.deleteByKey(ADDON_INSTALL_PREFFIX + addonInfo.getId()); + } + + private void clearAddonFiles(AddonInfo addonInfo) { + FileUtils.deleteQuietly(new File(PathKit.getWebRootPath(), "addons/" + addonInfo.getId())); + AddonUtil.forceDelete(addonInfo.buildJarFile()); + } + + private void invokeAddonUnisntallMethod(AddonInfo addonInfo) { + Addon addon = addonInfo.getAddon(); + if (addon != null) { + addon.onUninstall(addonInfo); + } + } + + /** + * 卸载插件中的native library + * + * @param addon + */ + private synchronized void unloadNativeLibs(Addon addon) { + if (addon == null) { + return; + } + try { + ClassLoader classLoader = addon.getClass().getClassLoader(); + Field field = ClassLoader.class.getDeclaredField("nativeLibraries"); + field.setAccessible(true); + Vector libs = (Vector) field.get(classLoader); + Iterator it = libs.iterator(); + Object o; + while (it.hasNext()) { + o = it.next(); + Method finalize = o.getClass().getDeclaredMethod("finalize", new Class[0]); + finalize.setAccessible(true); + finalize.invoke(o, new Object[0]); + it.remove(); + libs.remove(o); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void clearAddonCache(AddonInfo addonInfo) { + AddonUtil.clearAddonInfoCache(addonInfo.buildJarFile()); + addonInfo.setStatus(AddonInfo.STATUS_INIT); + addonsMap.remove(addonInfo.getId()); + } + + + public boolean start(String addonInfoId) { + return start(addonInfoId, true); + } + + + public boolean start(String addonInfoId, boolean withNotify) { + return start(getAddonInfo(addonInfoId), withNotify); + } + + /** + * 启动的动作: + * 1、标识插件启用 + * 2、添加插件的 controller、handler、interceptor 到对应的管理器 + * 3、若有 Model 类,启动新的 arp 插件 + * 4、回调插件的 onStart() + * 5、构建后台或用户中心菜单 + *

    + * 备注: + * 每次重启 JPress 都会调用 onStart() + * + * @param addonInfo + * @return + */ + public boolean start(AddonInfo addonInfo, boolean withNotify) { + try { + doStart(addonInfo); + if (withNotify) { + notifyAddonStarted(addonInfo.getId()); + } + return true; + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + stop(addonInfo.getId(), withNotify); + } + return false; + } + + private void doStart(AddonInfo addonInfo) { + + //添加插件的 Controllers + addControllers(addonInfo); + + //添加插件的 Handlers + addHandlers(addonInfo); + + //添加插件的 指令 + addDirectives(addonInfo); + + //添加插件的拦截器 + addInterceptors(addonInfo); + + //添加微信消息插件 + addWechatAddons(addonInfo); + + //启动插件的数据库连接插件 + startActiveRecordPlugin(addonInfo); + + //执行插件 onStart() 方法 + invokeStartMethod(addonInfo); + + //构建 JPress 应用的 url 映射 + buildApplicationActionMapping(); + + //设置插件的启动标识(状态) + setAddonStartedFalg(addonInfo); + + } + + + private void setAddonStartedFalg(AddonInfo addonInfo) { + addonInfo.setStatus(AddonInfo.STATUS_START); + OptionService optionService = Aop.get(OptionService.class); + optionService.saveOrUpdate(ADDON_START_PREFFIX + addonInfo.getId(), "true"); + + } + + private void buildApplicationActionMapping() { + AddonControllerManager.buildActionMapping(); + } + + private void invokeStartMethod(AddonInfo addonInfo) { + Addon addon = addonInfo.getAddon(); + if (addon != null) { + addon.onStart(addonInfo); + } + } + + private void startActiveRecordPlugin(AddonInfo addonInfo) { + List> modelClasses = addonInfo.getModels(); + if (modelClasses != null && !modelClasses.isEmpty()) { + + ActiveRecordPlugin arp = addonInfo.getOrCreateArp(); + + List tableList = getTableList(arp); + + for (Class c : modelClasses) { + + Table tableAnnotation = c.getAnnotation(Table.class); + boolean needAddMapping = true; + + if (tableList != null && !tableList.isEmpty()) { + for (com.jfinal.plugin.activerecord.Table t : tableList) { + if (t.getName().equals(AnnotationUtil.get(tableAnnotation.tableName()))) { + needAddMapping = false; + break; + } + } + } + + if (needAddMapping) { + if (StrUtil.isNotBlank(tableAnnotation.primaryKey())) { + arp.addMapping(AnnotationUtil.get(tableAnnotation.tableName()), AnnotationUtil.get(tableAnnotation.primaryKey()), (Class>) c); + } else { + arp.addMapping(AnnotationUtil.get(tableAnnotation.tableName()), (Class>) c); + } + } + } + addonInfo.setArp(arp); + arp.start(); + } + } + + private void addWechatAddons(AddonInfo addonInfo) { + List> wechatAddons = addonInfo.getWechatAddons(); + if (wechatAddons != null) { + for (Class c : wechatAddons) { + WechatAddonConfig config = c.getAnnotation(WechatAddonConfig.class); + WechatAddonInfo wechatAddon = new WechatAddonInfo(config, c); + WechatAddonManager.me().addWechatAddon(wechatAddon); + WechatAddonManager.me().doEnableAddon(config.id()); + } + } + } + + private void addInterceptors(AddonInfo addonInfo) { + List> interceptorClasses = addonInfo.getInterceptors(); + if (interceptorClasses != null) { + for (Class c : interceptorClasses) { + AddonInterceptorManager.addInterceptor(c); + } + } + } + + private void addDirectives(AddonInfo addonInfo) { + List> directives = addonInfo.getDirectives(); + if (directives != null) { + for (Class c : directives) { + JFinalDirective ann = c.getAnnotation(JFinalDirective.class); + String directiveName = AnnotationUtil.get(ann.value()); + // 先移除,后添加,若有相同指令的情况下, + // 后安装的插件会替换掉已经存在的指令 + RenderManager.me().getEngine().removeDirective(directiveName); + RenderManager.me().getEngine().addDirective(directiveName, c); + } + } + } + + private void addHandlers(AddonInfo addonInfo) { + List> handlerClasses = addonInfo.getHandlers(); + if (handlerClasses != null) { + for (Class c : handlerClasses) { + AddonHandlerManager.addHandler(c); + } + } + } + + private void addControllers(AddonInfo addonInfo) { + List> controllerClasses = addonInfo.getControllers(); + if (controllerClasses != null) { + for (Class c : controllerClasses) { + AddonControllerManager.addController(c, addonInfo.getId()); + } + } + } + + + public boolean stop(String id) { + return stop(id, true); + } + + public boolean stop(String id, boolean withNotify) { + try { + return stop(getAddonInfo(id)); + } finally { + if (withNotify) { + notifyAddonStoped(id); + } + } + } + + + public boolean stop(AddonInfo addonInfo) { + if (addonInfo == null){ + return false; + } + + //删除插件的所有Controller + try { + deleteControllers(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //删除插件的所有handler + try { + deleteHandlers(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //删除插件的所有指令 + try { + deleteDirectives(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //删除插件的所有拦截器 + try { + deleteInteceptors(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //移除所有的微信插件 + try { + deleteWechatAddons(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //停止插件的数据库访问 + try { + stopActiveRecordPlugin(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //移除所有的table数据 + try { + removeModelsCache(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //移除插件的模板缓存 + try { + removeTemplateCache(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //调用插件的 stop() 方法 + try { + invokeAddonStopMethod(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //重建整个JPress应用的ActionMapping映射 + try { + rebuildApplicationActionMapping(); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + //清除插件的状态,防止被重用 + try { + deleteStartedFlag(addonInfo); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + return true; + } + + private void deleteStartedFlag(AddonInfo addonInfo) { + addonInfo.setStatus(AddonInfo.STATUS_INSTALL); + OptionService optionService = Aop.get(OptionService.class); + optionService.deleteByKey(ADDON_START_PREFFIX + addonInfo.getId()); + } + + private void rebuildApplicationActionMapping() { + AddonControllerManager.buildActionMapping(); + } + + private void invokeAddonStopMethod(AddonInfo addonInfo) { + Addon addon = addonInfo.getAddon(); + if (addon != null) { + addon.onStop(addonInfo); + } + } + + private void removeTemplateCache(AddonInfo addonInfo) { + // 清除模板引擎的 field 和 method 缓存 + // 否则可能会出现 object is not an instance of declaring class 的异常 + // https://gitee.com/fuhai/jpress/issues/IS5YQ + FieldKit.clearCache(); + MethodKit.clearCache(); + TemplateManager.me().clearCache(false); + } + + private void stopActiveRecordPlugin(AddonInfo addonInfo) throws Exception { + ActiveRecordPlugin arp = addonInfo.getArp(); + if (arp != null && arp.stop()) { + clearStopedTableMapping(arp); + } + } + + private void clearStopedTableMapping(ActiveRecordPlugin arp) throws Exception { + + List tables = getTableList(arp); + + if (tables == null || tables.isEmpty()) { + return; + } + + + Field modelToTableMapField = TableMapping.class.getDeclaredField("modelToTableMap"); + modelToTableMapField.setAccessible(true); + Map>, com.jfinal.plugin.activerecord.Table> modelToTableMap = + (Map>, com.jfinal.plugin.activerecord.Table>) modelToTableMapField.get(TableMapping.me()); + + if (modelToTableMap == null || modelToTableMap.isEmpty()) { + return; + } + + for (com.jfinal.plugin.activerecord.Table table : tables) { + modelToTableMap.remove(table.getModelClass()); + } + } + + private List getTableList(ActiveRecordPlugin arp) { + try { + Field tableListField = ActiveRecordPlugin.class.getDeclaredField("tableList"); + tableListField.setAccessible(true); + return (List) tableListField.get(arp); + } catch (Exception ex) { + LogKit.error(ex.toString(), ex); + } + return null; + } + + /** + * 必须要移除所有的缓存,否则当插件卸载重新安装的时候, + * 缓存里的可能还存在数据,由于可能是内存缓存,所有可能导致Class转化异常的问题 + * PS:每次新安装的插件,都是一个新的 Classloader + * + * @param addonInfo + */ + private void removeModelsCache(AddonInfo addonInfo) { + List> modelClasses = addonInfo.getModels(); + if (modelClasses != null) { + modelClasses.forEach(aClass -> { + Table table = aClass.getAnnotation(Table.class); + String tableName = AnnotationUtil.get(table.tableName()); + JbootModelConfig.getConfig().getIdCache().removeAll(tableName); + Jboot.getCache().removeAll(tableName); + }); + } + } + + private void deleteWechatAddons(AddonInfo addonInfo) { + List> wechatAddons = addonInfo.getWechatAddons(); + if (wechatAddons != null) { + for (Class c : wechatAddons) { + WechatAddonConfig config = c.getAnnotation(WechatAddonConfig.class); + WechatAddonManager.me().deleteWechatAddon(AnnotationUtil.get(config.id())); + } + } + } + + private void deleteInteceptors(AddonInfo addonInfo) { + List> interceptorClasses = addonInfo.getInterceptors(); + if (interceptorClasses != null) { + for (Class c : interceptorClasses) { + AddonInterceptorManager.deleteInterceptor(c); + } + } + } + + private void deleteDirectives(AddonInfo addonInfo) { + List> directives = addonInfo.getDirectives(); + if (directives != null) { + for (Class c : directives) { + JFinalDirective ann = c.getAnnotation(JFinalDirective.class); + RenderManager.me().getEngine().removeDirective(AnnotationUtil.get(ann.value())); + } + } + } + + private void deleteHandlers(AddonInfo addonInfo) { + List> handlerClasses = addonInfo.getHandlers(); + if (handlerClasses != null) { + for (Class c : handlerClasses) { + AddonHandlerManager.deleteHandler(c); + } + } + } + + private void deleteControllers(AddonInfo addonInfo) { + List> controllerClasses = addonInfo.getControllers(); + if (controllerClasses != null) { + for (Class c : controllerClasses) { + AddonControllerManager.deleteController(c); + } + } + } + + + public Ret upgrade(File newAddonFile, String oldAddonId) { + AddonInfo oldAddon = AddonManager.me().getAddonInfo(oldAddonId); + if (oldAddon == null) { + return failRet("升级失败:无法读取旧的插件信息,可能该插件不存在。"); + } + + AddonInfo addon = AddonUtil.readSimpleAddonInfo(newAddonFile); + if (addon == null || StrUtil.isBlank(addon.getId())) { + return failRet("升级失败:无法读取新插件配置文件。"); + } + + if (!addon.getId().equals(oldAddonId)) { + return failRet("升级失败:新插件的ID和旧插件不一致。"); + } + + if (addon.getVersionCode() <= oldAddon.getVersionCode()) { + return failRet("升级失败:新插件的版本号必须大于已安装插件的版本号。"); + } + + boolean upgradeSuccess = false; + try { + upgradeSuccess = doUpgrade(newAddonFile, addon, oldAddon); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + upgradeSuccess = false; + } finally { + if (!upgradeSuccess) { + doUpgradeRollback(addon, oldAddon); + } + } + + return upgradeSuccess ? Ret.ok() : failRet("插件升级失败,请联系管理员。"); + } + + /** + * 开始升级 + * + * @param newAddon + * @param oldAddon + */ + private boolean doUpgrade(File newAddonFile, AddonInfo newAddon, AddonInfo oldAddon) throws IOException { + + //对已经安装的插件进行备份 + doBackupOldAddon(oldAddon); + + //解压缩新的资源文件 + doUnzipNewAddon(newAddonFile, newAddon); + + //获得已经进行 classloader 加载的 addon + if (!doInvokeAddonUpgradeMethod(newAddon, oldAddon)) { + return false; + } + + //设置该插件的状态为已经安装的状态 + if (!doSetAddonStatus(newAddon.getId())) { + return false; + } + + return true; + } + + private boolean doSetAddonStatus(String id) { + + AddonInfo addonInfo = addonsMap.get(id); + addonInfo.setStatus(AddonInfo.STATUS_INSTALL); + + OptionService optionService = Aop.get(OptionService.class); + return optionService.saveOrUpdate(ADDON_INSTALL_PREFFIX + id, "true") != null; + } + + private boolean doInvokeAddonUpgradeMethod(AddonInfo newAddon, AddonInfo oldAddon) { + + AddonUtil.clearAddonInfoCache(newAddon.buildJarFile()); + AddonInfo addon = AddonUtil.readAddonInfo(newAddon.buildJarFile()); + AddonUpgrader upgrader = addon.getAddonUpgrader(); + if (upgrader != null) { + boolean success = false; + try { + success = upgrader.onUpgrade(oldAddon, addon); + } finally { + if (!success) { + upgrader.onRollback(oldAddon, addon); + return false; + } + } + } + + + addonsMap.put(addon.getId(), addon); + return true; + } + + private void doUnzipNewAddon(File newAddonFile, AddonInfo newAddon) throws IOException { + File destAddonFile = newAddon.buildJarFile(); + FileUtils.moveFile(newAddonFile, destAddonFile); + + AddonUtil.unzipResources(newAddon); + } + + private void doBackupOldAddon(AddonInfo oldAddon) throws IOException { + + //备份 资源文件 + String resPath = PathKit.getWebRootPath() + + File.separator + + "addons" + + File.separator + + oldAddon.getId(); + + String resBakPath = resPath + "_bak"; + + //清空之前的备份文件 + File resBakPathDir = new File(resBakPath); + if (resBakPathDir.exists()) { + FileUtils.deleteDirectory(resBakPathDir); + } + + //备份资源文件 + FileUtils.moveDirectory(new File(resPath), resBakPathDir); + + File jarFile = oldAddon.buildJarFile(); + + File bakJarFile = new File(jarFile.getAbsolutePath() + "_bak"); + if (bakJarFile.exists()) { + FileUtils.deleteQuietly(bakJarFile); + } + + //备份jar文件 + FileUtils.moveFile(jarFile, bakJarFile); + } + + /** + * 升级回滚 + * + * @param addon + * @param oldAddon + */ + private void doUpgradeRollback(AddonInfo addon, AddonInfo oldAddon) { + + //删除刚刚升级安装的插件信息 + try { + doDeleteNewAddon(addon); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + + //恢复已经备份的插件信息 + try { + doRollBackBackups(addon); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + + //重置插件信息 + try { + doRestAddonInfo(oldAddon); + doSetAddonStatus(oldAddon.getId()); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + + } + + private void doRestAddonInfo(AddonInfo addonInfo) { + AddonUtil.clearAddonInfoCache(addonInfo.buildJarFile()); + AddonInfo addon = AddonUtil.readAddonInfo(addonInfo.buildJarFile()); + addonsMap.put(addon.getId(), addon); + } + + private void doRollBackBackups(AddonInfo addon) { + //备份 资源文件 + String resPath = PathKit.getWebRootPath() + + File.separator + + "addons" + + File.separator + + addon.getId(); + + String resBakPath = resPath + "_bak"; + + //恢复备份的资源文件 + try { + FileUtils.moveDirectory(new File(resBakPath), new File(resPath)); + } catch (IOException e) { + LOG.error(e.toString(), e); + } + + //恢复备份的jar文件 + try { + File bakJarFile = new File(addon.buildJarFile() + "_bak"); + FileUtils.moveFile(bakJarFile, addon.buildJarFile()); + } catch (IOException e) { + LOG.error(e.toString(), e); + } + + } + + private void doDeleteNewAddon(AddonInfo addon) { + AddonUtil.clearAddonInfoCache(addon.buildJarFile()); + + //删除已解压缩的资源文件 + FileUtils.deleteQuietly(new File(PathKit.getWebRootPath(), "addons/" + addon.getId())); + + //删除jar包 + AddonUtil.forceDelete(addon.buildJarFile()); + + //删除插件列表缓存 + addonsMap.remove(addon.getId()); + } + + private Ret failRet(String msg) { + return Ret.fail() + .set("success", false) + .setIfNotBlank("message", msg); + } + + //JbootEventListener.onEvent + @Override + public void onEvent(JbootEvent jbootEvent) { + init(); + } + + + private void notifyAddonInstall(String path) { + if (notifier != null){ + notifier.notifyAddonInstall(path); + } + } + + + private void notifyAddonStarted(String addonId) { + if (notifier != null){ + notifier.notifyAddonStarted(addonId); + } + } + + + private void notifyAddonStoped(String addonId) { + if (notifier != null){ + notifier.notifyAddonStoped(addonId); + } + } + + + private void notifyAddonUninstall(String addonId) { + if (notifier != null){ + notifier.notifyAddonUninstall(addonId); + } + } + + + public AddonNotifier getNotifier() { + return notifier; + } + + public void setNotifier(AddonNotifier notifier) { + this.notifier = notifier; + } + + public Map getAddonsMap() { + return addonsMap; + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/AddonNotifier.java b/jpress-core/src/main/java/io/jpress/core/addon/AddonNotifier.java index 158d53a14fdbd1a82f771ff9869081352fc4f79f..8d3f59612ed834e647e67f754268007448d0ec93 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/AddonNotifier.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/AddonNotifier.java @@ -1,20 +1,20 @@ -package io.jpress.core.addon; - -/** - * @author michael yang (fuhai999@gmail.com) - * @Date: 2020/3/1 - */ -public interface AddonNotifier { - - - public void notifyAddonInstall(String path) ; - - - public void notifyAddonStarted(String addonId) ; - - - public void notifyAddonStoped(String addonId) ; - - - public void notifyAddonUninstall(String addonId); -} +package io.jpress.core.addon; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/3/1 + */ +public interface AddonNotifier { + + + public void notifyAddonInstall(String path) ; + + + public void notifyAddonStarted(String addonId) ; + + + public void notifyAddonStoped(String addonId) ; + + + public void notifyAddonUninstall(String addonId); +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/AddonUpgrader.java b/jpress-core/src/main/java/io/jpress/core/addon/AddonUpgrader.java index 635bcddfc75c299fc09c3528096683b2ecc5bf2d..d879620bacc384ff29262c2fce76be60f46db3ed 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/AddonUpgrader.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/AddonUpgrader.java @@ -1,37 +1,37 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon; - -/** - * 插件的升级接口 - */ -public interface AddonUpgrader { - - /** - * 进行升级操作 - * @param oldAddon - * @param thisAddon - */ - public boolean onUpgrade(AddonInfo oldAddon,AddonInfo thisAddon); - - /** - * 升级失败的时候进行回滚 - * @param oldAddon - * @param thisAddon - */ - public void onRollback(AddonInfo oldAddon,AddonInfo thisAddon); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon; + +/** + * 插件的升级接口 + */ +public interface AddonUpgrader { + + /** + * 进行升级操作 + * @param oldAddon + * @param thisAddon + */ + public boolean onUpgrade(AddonInfo oldAddon,AddonInfo thisAddon); + + /** + * 升级失败的时候进行回滚 + * @param oldAddon + * @param thisAddon + */ + public void onRollback(AddonInfo oldAddon,AddonInfo thisAddon); + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/AddonUtil.java b/jpress-core/src/main/java/io/jpress/core/addon/AddonUtil.java index c9fcf1979ede75a33fe1bfdd300f532174b3f64e..3a5e5bc452a6589c5f0266aaa4de77a9ed3d9c35 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/AddonUtil.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/AddonUtil.java @@ -1,502 +1,502 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon; - -import com.jfinal.core.JFinal; -import com.jfinal.kit.LogKit; -import com.jfinal.kit.PathKit; -import com.jfinal.log.Log; -import com.jfinal.plugin.activerecord.ActiveRecordPlugin; -import com.jfinal.render.RenderManager; -import com.jfinal.template.Engine; -import com.jfinal.template.EngineConfig; -import com.jfinal.template.source.FileSourceFactory; -import com.jfinal.template.source.ISource; -import com.jfinal.template.stat.Parser; -import com.jfinal.template.stat.ast.Define; -import io.jboot.db.ArpManager; -import io.jboot.db.datasource.DataSourceBuilder; -import io.jboot.db.datasource.DataSourceConfig; -import io.jboot.db.datasource.DataSourceConfigManager; -import io.jboot.utils.FileUtil; -import io.jboot.utils.StrUtil; -import io.jpress.commons.utils.CommonsUtils; -import io.jpress.core.addon.template.AddonTemplateEnv; -import io.jpress.core.support.ehcache.EhcacheManager; -import org.apache.commons.lang3.StringUtils; - -import javax.sql.DataSource; -import java.io.*; -import java.lang.reflect.Field; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * 插件工具类 - */ -public class AddonUtil { - - private static final Log LOG = Log.getLog(AddonUtil.class); - private static List resourceSuffix = new ArrayList(); - - static { - resourceSuffix.add(".html"); - resourceSuffix.add(".htm"); - resourceSuffix.add(".css"); - resourceSuffix.add(".js"); - resourceSuffix.add(".jpg"); - resourceSuffix.add(".jpeg"); - resourceSuffix.add(".png"); - resourceSuffix.add(".bmp"); - resourceSuffix.add(".gif"); - resourceSuffix.add(".webp"); - resourceSuffix.add(".svg"); - resourceSuffix.add(".ttf"); - resourceSuffix.add(".woff"); - resourceSuffix.add(".woff2"); - resourceSuffix.add(".webp"); - resourceSuffix.add(".sql"); - } - - private static boolean isResource(String name) { - String suffix = FileUtil.getSuffix(name); - return suffix != null && resourceSuffix.contains(suffix.toLowerCase()) && !name.contains("..."); - } - - public static File resourceFile(String addonId, String path) { - return new File(getAddonBasePath(addonId), path); - } - - public static String getAddonBasePath(String addonId) { - StringBuilder basePath = new StringBuilder(PathKit.getWebRootPath()); - basePath.append(File.separator) - .append("addons") - .append(File.separator) - .append(addonId); - return basePath.toString(); - } - - public static String getViewPath(AddonInfo addonInfo, String path) { - if (addonInfo != null && addonInfo.isInstall()) { - StringBuilder basePath = new StringBuilder(); - basePath.append("/addons/") - .append(addonInfo.getId()) - .append(path); - return basePath.toString(); - } else { - return path; - } - } - - /** - * 解压 zip 或者 jar 的资源文件 - * - * @param addonInfo - * @throws IOException - */ - - public static void unzipResources(AddonInfo addonInfo) throws IOException { - String basePath = getAddonBasePath(addonInfo.getId()); - ZipFile zipFile = new ZipFile(addonInfo.buildJarFile()); - try { - Enumeration entryEnum = zipFile.entries(); - if (null != entryEnum) { - while (entryEnum.hasMoreElements()) { - OutputStream os = null; - InputStream is = null; - try { - ZipEntry zipEntry = (ZipEntry) entryEnum.nextElement(); - if (!zipEntry.isDirectory() && isResource(zipEntry.getName())) { - File targetFile = new File(basePath + File.separator + zipEntry.getName()); - if (!targetFile.getParentFile().exists()) { - targetFile.getParentFile().mkdirs(); - } - if (targetFile.exists()){ - forceDelete(targetFile); - } - os = new BufferedOutputStream(new FileOutputStream(targetFile)); - is = zipFile.getInputStream(zipEntry); - byte[] buffer = new byte[1024]; - int readLen = 0; - while ((readLen = is.read(buffer, 0, 1024)) > 0) { - os.write(buffer, 0, readLen); - } - } - } finally { - CommonsUtils.quietlyClose(is, os); - } - } - } - } finally { - CommonsUtils.quietlyClose(zipFile); - } - } - - - private static Map addonInfoCache = new ConcurrentHashMap<>(); - - - public static void clearAddonInfoCache(File addonFile) { - addonInfoCache.remove(addonFile.getAbsolutePath()); - } - - public static AddonInfo readAddonInfo(File addonFile) { - AddonInfo addonInfo = addonInfoCache.get(addonFile.getAbsolutePath()); - if (addonInfo == null) { - addonInfo = readSimpleAddonInfo(addonFile); - if (addonInfo == null) { - return null; - } - AddonClassLoader classLoader = null; - try { - classLoader = new AddonClassLoader(addonInfo); - List classNameList = classLoader.getClassNameList(); - for (String className : classNameList) { - EhcacheManager.addMapping(className, classLoader); - } - classLoader.load(); - } catch (IOException e) { - LogKit.error(e.toString(), e); - } finally { - //必须关闭,在Windows下才能卸载插件的时候删除jar包 - //否则一旦被 AddonClassLoader load之后,无法被删除 - CommonsUtils.quietlyClose(classLoader); - } - addonInfoCache.put(addonFile.getAbsolutePath(), addonInfo); - } - return addonInfo; - } - - - public static AddonInfo readSimpleAddonInfo(File addonFile) { - ZipFile zipFile = null; - Properties addonProp = null; - Properties addonConfigProp = null; - - String readmeText = null; - String changeLogText = null; - - try { - zipFile = new ZipFile(addonFile); - Enumeration entryEnum = zipFile.entries(); - if (null != entryEnum) { - while (entryEnum.hasMoreElements()) { - InputStream is = null; - try { - ZipEntry zipEntry = (ZipEntry) entryEnum.nextElement(); - if (StringUtils.equalsAnyIgnoreCase(zipEntry.getName(), "addon.txt", "addon.properties")) { - is = zipFile.getInputStream(zipEntry); - addonProp = new Properties(); - addonProp.load(new InputStreamReader(is, "utf-8")); - } - /** - * 独立的 config 配置信息 - */ - else if (StringUtils.equalsAnyIgnoreCase(zipEntry.getName(), "config.txt", "config.properties")) { - is = zipFile.getInputStream(zipEntry); - addonConfigProp = new Properties(); - addonConfigProp.load(new InputStreamReader(is, "utf-8")); - } - /** - * readme - */ - else if (StringUtils.equalsAnyIgnoreCase(zipEntry.getName(), "readme.txt")) { - is = zipFile.getInputStream(zipEntry); - readmeText = readString(is); - } - /** - * changeLog - */ - else if (StringUtils.equalsAnyIgnoreCase(zipEntry.getName(), "changelog.txt")) { - is = zipFile.getInputStream(zipEntry); - changeLogText = readString(is); - } - } finally { - CommonsUtils.quietlyClose(is); - } - } - } - } catch (IOException ex) { - ex.printStackTrace(); - } finally { - CommonsUtils.quietlyClose(zipFile); - } - - if (addonProp == null) { - return null; - } - - AddonInfo addonInfo = new AddonInfo(addonProp); - if (addonConfigProp != null) { - addonConfigProp.forEach((o, o2) -> { - if (o != null && o2 != null) { - addonInfo.addConfig(o.toString(), o2.toString()); - } - }); - } - - if (readmeText != null) { - addonInfo.setReadmeText(readmeText); - } - - if (changeLogText != null) { - addonInfo.setChangeLogText(changeLogText); - } - - return addonInfo; - } - - - private static String readString(InputStream stream) { - ByteArrayOutputStream baos = null; - try { - baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - for (int len = 0; (len = stream.read(buffer)) > 0; ) { - baos.write(buffer, 0, len); - } - return new String(baos.toByteArray(), JFinal.me().getConstants().getEncoding()); - } catch (Exception e) { - LogKit.error(e.toString(), e); - } finally { - CommonsUtils.quietlyClose(baos); - } - return null; - } - - /** - * 批量执行 Sql - * - * @param addonInfo - * @param sqlFilePath - * @throws SQLException - */ - public static void execSqlFile(AddonInfo addonInfo, String sqlFilePath) throws SQLException { - File file = resourceFile(addonInfo.getId(), sqlFilePath); - if (!file.exists()) { - LOG.warn("file not exists : " + file); - return; - } - String sql = FileUtil.readString(file); - if (StrUtil.isBlank(sql)) { - LOG.warn("can not read sql in : " + file); - return; - } - execSql(addonInfo, sql); - } - - /** - * 执行 Sql,可能用于在插件安装的时候进行执行 Sql 创建表等 - * 支持 Sql 批量执行 - * - * @param addonInfo - * @param sql - * @throws SQLException - */ - public static void execSql(AddonInfo addonInfo, String sql) throws SQLException { - DataSourceConfig dataSourceConfig = getDatasourceConfig(addonInfo); - DataSource dataSource = new DataSourceBuilder(dataSourceConfig).build(); - Connection conn = dataSource.getConnection(); - Statement pst = null; - try { - pst = conn.createStatement(); - sql = StrUtil.requireNonBlank(sql, "sql must not be null or blank."); - if (sql.contains(";")) { - String[] sqls = sql.split(";"); - for (String s : sqls) { - if (StrUtil.isNotBlank(s)) { - pst.addBatch(s); - } - } - } else { - pst.addBatch(sql); - } - // add by lixin 08.23 - pst.executeBatch(); - } finally { - // remove by lixin 08.23 sql 执行失败时导致连接不释放 - // pst.executeBatch(); - CommonsUtils.quietlyClose(pst, conn); - } - } - - - public static void addSharedFunction(AddonInfo addonInfo, String path) { - RenderManager.me().getEngine().addSharedFunction(getViewPath(addonInfo, path)); - } - - public static void removeSharedFunction(AddonInfo addonInfo, String path) { - try { - - String viewPath = getViewPath(addonInfo, path); - - Engine engine = RenderManager.me().getEngine(); - Field sharedFunctionMapField = EngineConfig.class.getDeclaredField("sharedFunctionMap"); - sharedFunctionMapField.setAccessible(true); - - Map sharedFunctionMap = (Map) sharedFunctionMapField.get(engine.getEngineConfig()); - if (sharedFunctionMap != null && !sharedFunctionMap.isEmpty()) { - - ISource source = new FileSourceFactory().getSource(engine.getBaseTemplatePath(), viewPath, "UTF-8"); - AddonTemplateEnv env = new AddonTemplateEnv(RenderManager.me().getEngine().getEngineConfig()); - new Parser(env, source.getContent(), viewPath).parse(); - - Map funcMap = env.getFunctionMap(); - if (funcMap != null) { - for (Map.Entry e : funcMap.entrySet()) { - sharedFunctionMap.remove(e.getKey()); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - - public static ActiveRecordPlugin createRecordPlugin(AddonInfo addonInfo) { - DataSourceConfig config = getDatasourceConfig(addonInfo); - config.setName(addonInfo.getId()); - config.setNeedAddMapping(false); - return ArpManager.me().createRecordPlugin(config); - } - - - private static DataSourceConfig getDatasourceConfig(AddonInfo addonInfo) { - Map config = addonInfo.getConfig(); - if (config == null || config.isEmpty()) { - return DataSourceConfigManager.me().getMainDatasourceConfig(); - } - - String url = config.get("db.url"); - String user = config.get("db.user"); - - /** - * must need url and user - */ - if (config == null || StrUtil.isBlank(url) || StrUtil.isBlank(user)) { - return DataSourceConfigManager.me().getMainDatasourceConfig(); - } - - - DataSourceConfig dsc = new DataSourceConfig(); - dsc.setUrl(url); - dsc.setUser(user); - dsc.setPassword(config.get("db.password")); - dsc.setConnectionInitSql(config.get("db.connectionInitSql")); - dsc.setPoolName(config.get("db.poolName")); - dsc.setSqlTemplate(config.get("db.sqlTemplate")); - dsc.setSqlTemplatePath(config.get("db.sqlTemplatePath")); - dsc.setFactory(config.get("db.factory")); - dsc.setShardingConfigYaml(config.get("db.shardingConfigYaml")); - dsc.setDbProFactory(config.get("db.dbProFactory")); - dsc.setTable(config.get("db.table")); - dsc.setExTable(config.get("db.exTable")); - dsc.setDialectClass(config.get("db.dialectClass")); - dsc.setActiveRecordPluginClass(config.get("db.activeRecordPluginClass")); - - String cachePrepStmts = config.get("db.cachePrepStmts"); - String prepStmtCacheSize = config.get("db.prepStmtCacheSize"); - String prepStmtCacheSqlLimit = config.get("db.prepStmtCacheSqlLimit"); - String maximumPoolSize = config.get("db.maximumPoolSize"); - String maxLifetime = config.get("db.maxLifetime"); - String minimumIdle = config.get("db.minimumIdle"); - - if (StrUtil.isNotBlank(cachePrepStmts)) { - dsc.setCachePrepStmts(Boolean.valueOf(cachePrepStmts)); - } - - if (StrUtil.isNotBlank(prepStmtCacheSize)) { - /** - * modify by lixin 07.31 - * dsc.setPrepStmtCacheSize(Integer.valueOf(cachePrepStmts)); - */ - dsc.setPrepStmtCacheSize(Integer.valueOf(prepStmtCacheSize)); - } - - if (StrUtil.isNotBlank(prepStmtCacheSqlLimit)) { - dsc.setPrepStmtCacheSqlLimit(Integer.valueOf(prepStmtCacheSqlLimit)); - } - - if (StrUtil.isNotBlank(maximumPoolSize)) { - dsc.setMaximumPoolSize(Integer.valueOf(maximumPoolSize)); - } - - if (StrUtil.isNotBlank(maxLifetime)) { - dsc.setMaxLifetime(Long.valueOf(maxLifetime)); - } - - if (StrUtil.isNotBlank(minimumIdle)) { - dsc.setMinimumIdle(Integer.valueOf(minimumIdle)); - } - - /** - * modify by lixin 07.31 - * String type = config.get("type"); - * String driverClassName = config.get("driverClassName"); - */ - - String type = config.get("db.type"); - String driverClassName = config.get("db.driverClassName"); - - if (StrUtil.isNotBlank(type)) { - dsc.setType(type); - } - - if (StrUtil.isNotBlank(driverClassName)) { - dsc.setDriverClassName(driverClassName); - } - - return dsc; - } - - /** - * 在windows系统下,当删除传刚刚 stop 的插件的时候,可能被占用无法删除 - * 但是过 "一段时间" 后,又可以删除了 - *

    - * 原因是:Classloader 进行 close() 的时候,无法及时释放资源造成的 - * - * @param file - * @return - */ - public static boolean forceDelete(File file) { - if (!file.exists()) { - return false; - } - - boolean result = file.delete(); - if (result) { - return true; - } - int tryCount = 0; - while (!result && tryCount++ < 10) { - System.gc(); - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - result = file.delete(); - } - return result; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon; + +import com.jfinal.core.JFinal; +import com.jfinal.kit.LogKit; +import com.jfinal.kit.PathKit; +import com.jfinal.log.Log; +import com.jfinal.plugin.activerecord.ActiveRecordPlugin; +import com.jfinal.render.RenderManager; +import com.jfinal.template.Engine; +import com.jfinal.template.EngineConfig; +import com.jfinal.template.source.FileSourceFactory; +import com.jfinal.template.source.ISource; +import com.jfinal.template.stat.Parser; +import com.jfinal.template.stat.ast.Define; +import io.jboot.db.ArpManager; +import io.jboot.db.datasource.DataSourceBuilder; +import io.jboot.db.datasource.DataSourceConfig; +import io.jboot.db.datasource.DataSourceConfigManager; +import io.jboot.utils.FileUtil; +import io.jboot.utils.StrUtil; +import io.jpress.commons.utils.CommonsUtils; +import io.jpress.core.addon.template.AddonTemplateEnv; +import io.jpress.core.support.ehcache.EhcacheManager; +import org.apache.commons.lang3.StringUtils; + +import javax.sql.DataSource; +import java.io.*; +import java.lang.reflect.Field; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * 插件工具类 + */ +public class AddonUtil { + + private static final Log LOG = Log.getLog(AddonUtil.class); + private static List resourceSuffix = new ArrayList(); + + static { + resourceSuffix.add(".html"); + resourceSuffix.add(".htm"); + resourceSuffix.add(".css"); + resourceSuffix.add(".js"); + resourceSuffix.add(".jpg"); + resourceSuffix.add(".jpeg"); + resourceSuffix.add(".png"); + resourceSuffix.add(".bmp"); + resourceSuffix.add(".gif"); + resourceSuffix.add(".webp"); + resourceSuffix.add(".svg"); + resourceSuffix.add(".ttf"); + resourceSuffix.add(".woff"); + resourceSuffix.add(".woff2"); + resourceSuffix.add(".webp"); + resourceSuffix.add(".sql"); + } + + private static boolean isResource(String name) { + String suffix = FileUtil.getSuffix(name); + return suffix != null && resourceSuffix.contains(suffix.toLowerCase()) && !name.contains("..."); + } + + public static File resourceFile(String addonId, String path) { + return new File(getAddonBasePath(addonId), path); + } + + public static String getAddonBasePath(String addonId) { + StringBuilder basePath = new StringBuilder(PathKit.getWebRootPath()); + basePath.append(File.separator) + .append("addons") + .append(File.separator) + .append(addonId); + return basePath.toString(); + } + + public static String getViewPath(AddonInfo addonInfo, String path) { + if (addonInfo != null && addonInfo.isInstall()) { + StringBuilder basePath = new StringBuilder(); + basePath.append("/addons/") + .append(addonInfo.getId()) + .append(path); + return basePath.toString(); + } else { + return path; + } + } + + /** + * 解压 zip 或者 jar 的资源文件 + * + * @param addonInfo + * @throws IOException + */ + + public static void unzipResources(AddonInfo addonInfo) throws IOException { + String basePath = getAddonBasePath(addonInfo.getId()); + ZipFile zipFile = new ZipFile(addonInfo.buildJarFile()); + try { + Enumeration entryEnum = zipFile.entries(); + if (null != entryEnum) { + while (entryEnum.hasMoreElements()) { + OutputStream os = null; + InputStream is = null; + try { + ZipEntry zipEntry = (ZipEntry) entryEnum.nextElement(); + if (!zipEntry.isDirectory() && isResource(zipEntry.getName())) { + File targetFile = new File(basePath + File.separator + zipEntry.getName()); + if (!targetFile.getParentFile().exists()) { + targetFile.getParentFile().mkdirs(); + } + if (targetFile.exists()){ + forceDelete(targetFile); + } + os = new BufferedOutputStream(new FileOutputStream(targetFile)); + is = zipFile.getInputStream(zipEntry); + byte[] buffer = new byte[1024]; + int readLen = 0; + while ((readLen = is.read(buffer, 0, 1024)) > 0) { + os.write(buffer, 0, readLen); + } + } + } finally { + CommonsUtils.quietlyClose(is, os); + } + } + } + } finally { + CommonsUtils.quietlyClose(zipFile); + } + } + + + private static Map addonInfoCache = new ConcurrentHashMap<>(); + + + public static void clearAddonInfoCache(File addonFile) { + addonInfoCache.remove(addonFile.getAbsolutePath()); + } + + public static AddonInfo readAddonInfo(File addonFile) { + AddonInfo addonInfo = addonInfoCache.get(addonFile.getAbsolutePath()); + if (addonInfo == null) { + addonInfo = readSimpleAddonInfo(addonFile); + if (addonInfo == null) { + return null; + } + AddonClassLoader classLoader = null; + try { + classLoader = new AddonClassLoader(addonInfo); + List classNameList = classLoader.getClassNameList(); + for (String className : classNameList) { + EhcacheManager.addMapping(className, classLoader); + } + classLoader.load(); + } catch (IOException e) { + LogKit.error(e.toString(), e); + } finally { + //必须关闭,在Windows下才能卸载插件的时候删除jar包 + //否则一旦被 AddonClassLoader load之后,无法被删除 + CommonsUtils.quietlyClose(classLoader); + } + addonInfoCache.put(addonFile.getAbsolutePath(), addonInfo); + } + return addonInfo; + } + + + public static AddonInfo readSimpleAddonInfo(File addonFile) { + ZipFile zipFile = null; + Properties addonProp = null; + Properties addonConfigProp = null; + + String readmeText = null; + String changeLogText = null; + + try { + zipFile = new ZipFile(addonFile); + Enumeration entryEnum = zipFile.entries(); + if (null != entryEnum) { + while (entryEnum.hasMoreElements()) { + InputStream is = null; + try { + ZipEntry zipEntry = (ZipEntry) entryEnum.nextElement(); + if (StringUtils.equalsAnyIgnoreCase(zipEntry.getName(), "addon.txt", "addon.properties")) { + is = zipFile.getInputStream(zipEntry); + addonProp = new Properties(); + addonProp.load(new InputStreamReader(is, "utf-8")); + } + /** + * 独立的 config 配置信息 + */ + else if (StringUtils.equalsAnyIgnoreCase(zipEntry.getName(), "config.txt", "config.properties")) { + is = zipFile.getInputStream(zipEntry); + addonConfigProp = new Properties(); + addonConfigProp.load(new InputStreamReader(is, "utf-8")); + } + /** + * readme + */ + else if (StringUtils.equalsAnyIgnoreCase(zipEntry.getName(), "readme.txt")) { + is = zipFile.getInputStream(zipEntry); + readmeText = readString(is); + } + /** + * changeLog + */ + else if (StringUtils.equalsAnyIgnoreCase(zipEntry.getName(), "changelog.txt")) { + is = zipFile.getInputStream(zipEntry); + changeLogText = readString(is); + } + } finally { + CommonsUtils.quietlyClose(is); + } + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } finally { + CommonsUtils.quietlyClose(zipFile); + } + + if (addonProp == null) { + return null; + } + + AddonInfo addonInfo = new AddonInfo(addonProp); + if (addonConfigProp != null) { + addonConfigProp.forEach((o, o2) -> { + if (o != null && o2 != null) { + addonInfo.addConfig(o.toString(), o2.toString()); + } + }); + } + + if (readmeText != null) { + addonInfo.setReadmeText(readmeText); + } + + if (changeLogText != null) { + addonInfo.setChangeLogText(changeLogText); + } + + return addonInfo; + } + + + private static String readString(InputStream stream) { + ByteArrayOutputStream baos = null; + try { + baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + for (int len = 0; (len = stream.read(buffer)) > 0; ) { + baos.write(buffer, 0, len); + } + return new String(baos.toByteArray(), JFinal.me().getConstants().getEncoding()); + } catch (Exception e) { + LogKit.error(e.toString(), e); + } finally { + CommonsUtils.quietlyClose(baos); + } + return null; + } + + /** + * 批量执行 Sql + * + * @param addonInfo + * @param sqlFilePath + * @throws SQLException + */ + public static void execSqlFile(AddonInfo addonInfo, String sqlFilePath) throws SQLException { + File file = resourceFile(addonInfo.getId(), sqlFilePath); + if (!file.exists()) { + LOG.warn("file not exists : " + file); + return; + } + String sql = FileUtil.readString(file); + if (StrUtil.isBlank(sql)) { + LOG.warn("can not read sql in : " + file); + return; + } + execSql(addonInfo, sql); + } + + /** + * 执行 Sql,可能用于在插件安装的时候进行执行 Sql 创建表等 + * 支持 Sql 批量执行 + * + * @param addonInfo + * @param sql + * @throws SQLException + */ + public static void execSql(AddonInfo addonInfo, String sql) throws SQLException { + DataSourceConfig dataSourceConfig = getDatasourceConfig(addonInfo); + DataSource dataSource = new DataSourceBuilder(dataSourceConfig).build(); + Connection conn = dataSource.getConnection(); + Statement pst = null; + try { + pst = conn.createStatement(); + sql = StrUtil.requireNonBlank(sql, "sql must not be null or blank."); + if (sql.contains(";")) { + String[] sqls = sql.split(";"); + for (String s : sqls) { + if (StrUtil.isNotBlank(s)) { + pst.addBatch(s); + } + } + } else { + pst.addBatch(sql); + } + // add by lixin 08.23 + pst.executeBatch(); + } finally { + // remove by lixin 08.23 sql 执行失败时导致连接不释放 + // pst.executeBatch(); + CommonsUtils.quietlyClose(pst, conn); + } + } + + + public static void addSharedFunction(AddonInfo addonInfo, String path) { + RenderManager.me().getEngine().addSharedFunction(getViewPath(addonInfo, path)); + } + + public static void removeSharedFunction(AddonInfo addonInfo, String path) { + try { + + String viewPath = getViewPath(addonInfo, path); + + Engine engine = RenderManager.me().getEngine(); + Field sharedFunctionMapField = EngineConfig.class.getDeclaredField("sharedFunctionMap"); + sharedFunctionMapField.setAccessible(true); + + Map sharedFunctionMap = (Map) sharedFunctionMapField.get(engine.getEngineConfig()); + if (sharedFunctionMap != null && !sharedFunctionMap.isEmpty()) { + + ISource source = new FileSourceFactory().getSource(engine.getBaseTemplatePath(), viewPath, "UTF-8"); + AddonTemplateEnv env = new AddonTemplateEnv(RenderManager.me().getEngine().getEngineConfig()); + new Parser(env, source.getContent(), viewPath).parse(); + + Map funcMap = env.getFunctionMap(); + if (funcMap != null) { + for (Map.Entry e : funcMap.entrySet()) { + sharedFunctionMap.remove(e.getKey()); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + public static ActiveRecordPlugin createRecordPlugin(AddonInfo addonInfo) { + DataSourceConfig config = getDatasourceConfig(addonInfo); + config.setName(addonInfo.getId()); + config.setNeedAddMapping(false); + return ArpManager.me().createRecordPlugin(config); + } + + + private static DataSourceConfig getDatasourceConfig(AddonInfo addonInfo) { + Map config = addonInfo.getConfig(); + if (config == null || config.isEmpty()) { + return DataSourceConfigManager.me().getMainDatasourceConfig(); + } + + String url = config.get("db.url"); + String user = config.get("db.user"); + + /** + * must need url and user + */ + if (config == null || StrUtil.isBlank(url) || StrUtil.isBlank(user)) { + return DataSourceConfigManager.me().getMainDatasourceConfig(); + } + + + DataSourceConfig dsc = new DataSourceConfig(); + dsc.setUrl(url); + dsc.setUser(user); + dsc.setPassword(config.get("db.password")); + dsc.setConnectionInitSql(config.get("db.connectionInitSql")); + dsc.setPoolName(config.get("db.poolName")); + dsc.setSqlTemplate(config.get("db.sqlTemplate")); + dsc.setSqlTemplatePath(config.get("db.sqlTemplatePath")); + dsc.setFactory(config.get("db.factory")); + dsc.setShardingConfigYaml(config.get("db.shardingConfigYaml")); + dsc.setDbProFactory(config.get("db.dbProFactory")); + dsc.setTable(config.get("db.table")); + dsc.setExTable(config.get("db.exTable")); + dsc.setDialectClass(config.get("db.dialectClass")); + dsc.setActiveRecordPluginClass(config.get("db.activeRecordPluginClass")); + + String cachePrepStmts = config.get("db.cachePrepStmts"); + String prepStmtCacheSize = config.get("db.prepStmtCacheSize"); + String prepStmtCacheSqlLimit = config.get("db.prepStmtCacheSqlLimit"); + String maximumPoolSize = config.get("db.maximumPoolSize"); + String maxLifetime = config.get("db.maxLifetime"); + String minimumIdle = config.get("db.minimumIdle"); + + if (StrUtil.isNotBlank(cachePrepStmts)) { + dsc.setCachePrepStmts(Boolean.valueOf(cachePrepStmts)); + } + + if (StrUtil.isNotBlank(prepStmtCacheSize)) { + /** + * modify by lixin 07.31 + * dsc.setPrepStmtCacheSize(Integer.valueOf(cachePrepStmts)); + */ + dsc.setPrepStmtCacheSize(Integer.valueOf(prepStmtCacheSize)); + } + + if (StrUtil.isNotBlank(prepStmtCacheSqlLimit)) { + dsc.setPrepStmtCacheSqlLimit(Integer.valueOf(prepStmtCacheSqlLimit)); + } + + if (StrUtil.isNotBlank(maximumPoolSize)) { + dsc.setMaximumPoolSize(Integer.valueOf(maximumPoolSize)); + } + + if (StrUtil.isNotBlank(maxLifetime)) { + dsc.setMaxLifetime(Long.valueOf(maxLifetime)); + } + + if (StrUtil.isNotBlank(minimumIdle)) { + dsc.setMinimumIdle(Integer.valueOf(minimumIdle)); + } + + /** + * modify by lixin 07.31 + * String type = config.get("type"); + * String driverClassName = config.get("driverClassName"); + */ + + String type = config.get("db.type"); + String driverClassName = config.get("db.driverClassName"); + + if (StrUtil.isNotBlank(type)) { + dsc.setType(type); + } + + if (StrUtil.isNotBlank(driverClassName)) { + dsc.setDriverClassName(driverClassName); + } + + return dsc; + } + + /** + * 在windows系统下,当删除传刚刚 stop 的插件的时候,可能被占用无法删除 + * 但是过 "一段时间" 后,又可以删除了 + *

    + * 原因是:Classloader 进行 close() 的时候,无法及时释放资源造成的 + * + * @param file + * @return + */ + public static boolean forceDelete(File file) { + if (!file.exists()) { + return false; + } + + boolean result = file.delete(); + if (result) { + return true; + } + int tryCount = 0; + while (!result && tryCount++ < 10) { + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + result = file.delete(); + } + return result; + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/annotation/GlobalInterceptor.java b/jpress-core/src/main/java/io/jpress/core/addon/annotation/GlobalInterceptor.java index 4ad7ff7f74926d53d06bffeb854e8826930a7e59..9b86ed9d51fa43ac8705123b569ecded72d81ad9 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/annotation/GlobalInterceptor.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/annotation/GlobalInterceptor.java @@ -1,28 +1,28 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon.annotation; - -import java.lang.annotation.*; - -/** - * NotGlobalInterceptor - */ -@Inherited -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE}) -public @interface GlobalInterceptor { - +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon.annotation; + +import java.lang.annotation.*; + +/** + * NotGlobalInterceptor + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface GlobalInterceptor { + } \ No newline at end of file diff --git a/jpress-core/src/main/java/io/jpress/core/addon/controller/AddonControllerManager.java b/jpress-core/src/main/java/io/jpress/core/addon/controller/AddonControllerManager.java index 79f9845ca34ab02356d6d7a613157a7938fd6493..cde251fd8df6727bc247bd9ccac60a38dc305fb4 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/controller/AddonControllerManager.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/controller/AddonControllerManager.java @@ -1,236 +1,236 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon.controller; - - -import com.jfinal.aop.Interceptor; -import com.jfinal.aop.Invocation; -import com.jfinal.config.Routes; -import com.jfinal.core.Action; -import com.jfinal.core.ActionMapping; -import com.jfinal.core.Controller; -import io.jboot.utils.AnnotationUtil; -import io.jboot.utils.StrUtil; -import io.jboot.web.controller.annotation.RequestMapping; -import io.jpress.core.menu.MenuItem; -import io.jpress.core.menu.MenuManager; -import io.jpress.core.menu.annotation.AdminMenu; -import io.jpress.core.menu.annotation.UCenterMenu; -import io.jpress.web.interceptor.JPressInterceptor; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -public class AddonControllerManager { - - private static Routes addonRoutes = new AddonRoutes(); - private static AddonActionMapping actionMapping = new AddonActionMapping(addonRoutes); - - private static Map controllerAddonMapping = new ConcurrentHashMap<>(); - - - public static void addController(Class controllerClass, String addonId) { - RequestMapping mapping = controllerClass.getAnnotation(RequestMapping.class); - if (mapping == null) { - return; - } - - String path = AnnotationUtil.get(mapping.value()); - if (path == null) { - return; - } - - // 尝试去清除 Controller 以保障绝对安全, 虽然插件在 stop() 的时候会去清除 - // 但是由于可能 stop() 出错等原因,没有执行到 deletController 的操作 - deleteController(controllerClass); - - String viewPath = AnnotationUtil.get(mapping.viewPath()); - if (StrUtil.isBlank(viewPath)) { - viewPath = "/"; - } else if (viewPath.indexOf("/") != 0) { - viewPath = "/" + viewPath; - } - - addonRoutes.add(path, controllerClass, "/addons/" + addonId + viewPath); - controllerAddonMapping.put(controllerClass, addonId); - } - - public static List getAllActionKeys() { - return actionMapping.getAllActionKeys(); - } - - - public static void deleteController(Class c) { - RequestMapping mapping = c.getAnnotation(RequestMapping.class); - if (mapping == null) { - return; - } - - String value = AnnotationUtil.get(mapping.value()); - if (value == null) { - return; - } - - addonRoutes.getRouteItemList().removeIf(route -> route.getControllerKey().equals(value)); - Routes.getControllerKeySet().removeIf(actionKey -> Objects.equals(actionKey, value)); - controllerAddonMapping.remove(c); - } - - - public static void buildActionMapping() { - deleteAddonMenus(); - actionMapping.buildActionMapping(); - addAddonMenus(); - } - - - private static void addAddonMenus() { - MenuManager.me().addMenuItems(buildAdminMenuItems()); - MenuManager.me().addMenuItems(buildUcenterMenuItems()); - } - - - private static void deleteAddonMenus() { - List adminMenuItems = buildAdminMenuItems(); - for (MenuItem menuItem : adminMenuItems) { - MenuManager.me().deleteMenuItem(menuItem.getId()); - } - List ucenterMenuItems = buildUcenterMenuItems(); - for (MenuItem menuItem : ucenterMenuItems) { - MenuManager.me().deleteMenuItem(menuItem.getId()); - } - } - - - private static List buildUcenterMenuItems() { - List adminMenuItems = new ArrayList<>(); - List allActionKeys = actionMapping.getAllActionKeys(); - - String[] urlPara = new String[1]; - for (String actionKey : allActionKeys) { - // 只处理 ucenter 开头的菜单 - if (actionKey.startsWith("/ucenter")) { - - Action action = getAction(actionKey, urlPara); - if (action == null) { - continue; - } - - UCenterMenu uCenterMenu = action.getMethod().getAnnotation(UCenterMenu.class); - if (uCenterMenu == null) { - continue; - } - - adminMenuItems.add(new MenuItem(uCenterMenu, actionKey)); - } - } - - return adminMenuItems; - } - - public static List buildAdminMenuItems() { - - List adminMenuItems = new ArrayList<>(); - List allActionKeys = actionMapping.getAllActionKeys(); - - String[] urlPara = new String[1]; - for (String actionKey : allActionKeys) { - // 只处理后台的权限 和 API的权限 - if (actionKey.startsWith("/admin")) { - - Action action = getAction(actionKey, urlPara); - if (action == null) { - continue; - } - - AdminMenu adminMenu = action.getMethod().getAnnotation(AdminMenu.class); - if (adminMenu == null) { - continue; - } - - adminMenuItems.add(new MenuItem(adminMenu, actionKey)); - } - } - - return adminMenuItems; - } - - public static Action getAction(String target, String[] urlPara) { - return actionMapping.getAction(target, urlPara); - } - - - /** - * 此拦截器是作用于所有的插件加载进来的 Controller - * 设置了 APATH 这个常量,方便插件自己的 Controller 去渲染自己目录下的静态资源文件,例如:css、js等 - * 例如,在html引入自己插件下的css内容,可以这么写 - * - */ - public static class AddonControllerInterceptor implements Interceptor { - @Override - public void intercept(Invocation inv) { - String addonId = controllerAddonMapping.get(inv.getController().getClass()); - inv.getController().set(JPressInterceptor.ADDON_PATH_KEY, "/addons/" + addonId); - inv.invoke(); - } - } - - - /** - * 自定义自己的ActionMapping的原因主要有以下几点 - *

    - * 1、ActionMapping 的 mapping 是 hashMap,随时对这个 mapping 进行操作可能存在线程不安全的问题,所以需要修改为 ConcurrentHashMap - * 2、需要把 buildActionMapping() 方法给公布出来,才能在对 mapping 进行操作的时候重新构建 actionKey->Controller 的映射关系 - */ - public static class AddonActionMapping extends ActionMapping { - - public AddonActionMapping(Routes routes) { - super(routes); - this.mapping = new ConcurrentHashMap<>(); - } - - @Override - public void buildActionMapping() { - super.buildActionMapping(); - } - - - @Override - public Action getAction(String url, String[] urlPara) { - return super.getAction(url, urlPara); - } - } - - - public static class AddonRoutes extends Routes { - - public AddonRoutes() { - //setClearAfterMapping(false) 不让 AddonActionMapping 在构建完毕后对已经添加的 Routes 进行清除的工作 - setClearAfterMapping(false); - - //通过 AddonControllerInterceptor 拦截器设置每个插件自己的资源路径 - addInterceptor(new AddonControllerInterceptor()); - } - - @Override - public void config() { - //do nothing - } - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon.controller; + + +import com.jfinal.aop.Interceptor; +import com.jfinal.aop.Invocation; +import com.jfinal.config.Routes; +import com.jfinal.core.Action; +import com.jfinal.core.ActionMapping; +import com.jfinal.core.Controller; +import io.jboot.utils.AnnotationUtil; +import io.jboot.utils.StrUtil; +import io.jboot.web.controller.annotation.RequestMapping; +import io.jpress.core.menu.MenuItem; +import io.jpress.core.menu.MenuManager; +import io.jpress.core.menu.annotation.AdminMenu; +import io.jpress.core.menu.annotation.UCenterMenu; +import io.jpress.web.interceptor.JPressInterceptor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +public class AddonControllerManager { + + private static Routes addonRoutes = new AddonRoutes(); + private static AddonActionMapping actionMapping = new AddonActionMapping(addonRoutes); + + private static Map controllerAddonMapping = new ConcurrentHashMap<>(); + + + public static void addController(Class controllerClass, String addonId) { + RequestMapping mapping = controllerClass.getAnnotation(RequestMapping.class); + if (mapping == null) { + return; + } + + String path = AnnotationUtil.get(mapping.value()); + if (path == null) { + return; + } + + // 尝试去清除 Controller 以保障绝对安全, 虽然插件在 stop() 的时候会去清除 + // 但是由于可能 stop() 出错等原因,没有执行到 deletController 的操作 + deleteController(controllerClass); + + String viewPath = AnnotationUtil.get(mapping.viewPath()); + if (StrUtil.isBlank(viewPath)) { + viewPath = "/"; + } else if (viewPath.indexOf("/") != 0) { + viewPath = "/" + viewPath; + } + + addonRoutes.add(path, controllerClass, "/addons/" + addonId + viewPath); + controllerAddonMapping.put(controllerClass, addonId); + } + + public static List getAllActionKeys() { + return actionMapping.getAllActionKeys(); + } + + + public static void deleteController(Class c) { + RequestMapping mapping = c.getAnnotation(RequestMapping.class); + if (mapping == null) { + return; + } + + String value = AnnotationUtil.get(mapping.value()); + if (value == null) { + return; + } + + addonRoutes.getRouteItemList().removeIf(route -> route.getControllerKey().equals(value)); + Routes.getControllerKeySet().removeIf(actionKey -> Objects.equals(actionKey, value)); + controllerAddonMapping.remove(c); + } + + + public static void buildActionMapping() { + deleteAddonMenus(); + actionMapping.buildActionMapping(); + addAddonMenus(); + } + + + private static void addAddonMenus() { + MenuManager.me().addMenuItems(buildAdminMenuItems()); + MenuManager.me().addMenuItems(buildUcenterMenuItems()); + } + + + private static void deleteAddonMenus() { + List adminMenuItems = buildAdminMenuItems(); + for (MenuItem menuItem : adminMenuItems) { + MenuManager.me().deleteMenuItem(menuItem.getId()); + } + List ucenterMenuItems = buildUcenterMenuItems(); + for (MenuItem menuItem : ucenterMenuItems) { + MenuManager.me().deleteMenuItem(menuItem.getId()); + } + } + + + private static List buildUcenterMenuItems() { + List adminMenuItems = new ArrayList<>(); + List allActionKeys = actionMapping.getAllActionKeys(); + + String[] urlPara = new String[1]; + for (String actionKey : allActionKeys) { + // 只处理 ucenter 开头的菜单 + if (actionKey.startsWith("/ucenter")) { + + Action action = getAction(actionKey, urlPara); + if (action == null) { + continue; + } + + UCenterMenu uCenterMenu = action.getMethod().getAnnotation(UCenterMenu.class); + if (uCenterMenu == null) { + continue; + } + + adminMenuItems.add(new MenuItem(uCenterMenu, actionKey)); + } + } + + return adminMenuItems; + } + + public static List buildAdminMenuItems() { + + List adminMenuItems = new ArrayList<>(); + List allActionKeys = actionMapping.getAllActionKeys(); + + String[] urlPara = new String[1]; + for (String actionKey : allActionKeys) { + // 只处理后台的权限 和 API的权限 + if (actionKey.startsWith("/admin")) { + + Action action = getAction(actionKey, urlPara); + if (action == null) { + continue; + } + + AdminMenu adminMenu = action.getMethod().getAnnotation(AdminMenu.class); + if (adminMenu == null) { + continue; + } + + adminMenuItems.add(new MenuItem(adminMenu, actionKey)); + } + } + + return adminMenuItems; + } + + public static Action getAction(String target, String[] urlPara) { + return actionMapping.getAction(target, urlPara); + } + + + /** + * 此拦截器是作用于所有的插件加载进来的 Controller + * 设置了 APATH 这个常量,方便插件自己的 Controller 去渲染自己目录下的静态资源文件,例如:css、js等 + * 例如,在html引入自己插件下的css内容,可以这么写 + * + */ + public static class AddonControllerInterceptor implements Interceptor { + @Override + public void intercept(Invocation inv) { + String addonId = controllerAddonMapping.get(inv.getController().getClass()); + inv.getController().set(JPressInterceptor.ADDON_PATH_KEY, "/addons/" + addonId); + inv.invoke(); + } + } + + + /** + * 自定义自己的ActionMapping的原因主要有以下几点 + *

    + * 1、ActionMapping 的 mapping 是 hashMap,随时对这个 mapping 进行操作可能存在线程不安全的问题,所以需要修改为 ConcurrentHashMap + * 2、需要把 buildActionMapping() 方法给公布出来,才能在对 mapping 进行操作的时候重新构建 actionKey->Controller 的映射关系 + */ + public static class AddonActionMapping extends ActionMapping { + + public AddonActionMapping(Routes routes) { + super(routes); + this.mapping = new ConcurrentHashMap<>(); + } + + @Override + public void buildActionMapping() { + super.buildActionMapping(); + } + + + @Override + public Action getAction(String url, String[] urlPara) { + return super.getAction(url, urlPara); + } + } + + + public static class AddonRoutes extends Routes { + + public AddonRoutes() { + //setClearAfterMapping(false) 不让 AddonActionMapping 在构建完毕后对已经添加的 Routes 进行清除的工作 + setClearAfterMapping(false); + + //通过 AddonControllerInterceptor 拦截器设置每个插件自己的资源路径 + addInterceptor(new AddonControllerInterceptor()); + } + + @Override + public void config() { + //do nothing + } + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/controller/AddonControllerProcesser.java b/jpress-core/src/main/java/io/jpress/core/addon/controller/AddonControllerProcesser.java index 87d9140e08572e0a08a3db7c7a0155fea8276d24..5359a226a1e7ed14018f46542b1ff3dd2429aa7d 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/controller/AddonControllerProcesser.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/controller/AddonControllerProcesser.java @@ -1,41 +1,41 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon.controller; - -import com.jfinal.core.Action; -import io.jboot.web.handler.JbootActionHandler; - - -public class AddonControllerProcesser extends JbootActionHandler { - - - @Override - public Action getAction(String target, String[] urlPara) { - Action action = super.getAction(target, urlPara); - if (action == null) { - return AddonControllerManager.getAction(target, urlPara); - } - - if (!target.equals(action.getActionKey())) { - Action addonAction = AddonControllerManager.getAction(target, urlPara); - if (addonAction != null && target.equals(addonAction.getActionKey())) { - return addonAction; - } - } - return action; - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon.controller; + +import com.jfinal.core.Action; +import io.jboot.web.handler.JbootActionHandler; + + +public class AddonControllerProcesser extends JbootActionHandler { + + + @Override + public Action getAction(String target, String[] urlPara) { + Action action = super.getAction(target, urlPara); + if (action == null) { + return AddonControllerManager.getAction(target, urlPara); + } + + if (!target.equals(action.getActionKey())) { + Action addonAction = AddonControllerManager.getAction(target, urlPara); + if (addonAction != null && target.equals(addonAction.getActionKey())) { + return addonAction; + } + } + return action; + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/handler/AddonHandlerManager.java b/jpress-core/src/main/java/io/jpress/core/addon/handler/AddonHandlerManager.java index 27155303dd6b860fd727b033c9486c58a727947c..1261776da97b5ca18fb90766e5132c84f164a5a7 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/handler/AddonHandlerManager.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/handler/AddonHandlerManager.java @@ -1,69 +1,69 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon.handler; - - -import com.jfinal.handler.Handler; -import com.jfinal.handler.HandlerFactory; -import io.jboot.utils.ClassUtil; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class AddonHandlerManager { - - private static Handler processHandler = null; - private static List handlers = Collections.synchronizedList(new ArrayList<>()); - private static boolean reset = true; - - public static Handler getProcessHandler(Handler next) { - - if (processHandler == null || reset) { - synchronized (AddonHandlerManager.class) { - if (processHandler == null || reset) { - processHandler = buildHandler(next); - reset = false; - } - } - } - return processHandler; - } - - private static synchronized Handler buildHandler(Handler next) { - // 当没有插件的 handler 的时候,返回原始的 handler - if (handlers.isEmpty()) { - return next; - } - - return HandlerFactory.getHandler(handlers, next); - } - - public static void addHandler(Class c) { - handlers.removeIf(handler -> ClassUtil.getUsefulClass(handler.getClass()).getName().equals(c.getName())); - handlers.add(ClassUtil.newInstance(c)); - resetProcessHandler(); - } - - public static void deleteHandler(Class c) { - handlers.removeIf(handler -> ClassUtil.getUsefulClass(handler.getClass()).getName().equals(c.getName())); - resetProcessHandler(); - } - - private static void resetProcessHandler() { - reset = true; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon.handler; + + +import com.jfinal.handler.Handler; +import com.jfinal.handler.HandlerFactory; +import io.jboot.utils.ClassUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class AddonHandlerManager { + + private static Handler processHandler = null; + private static List handlers = Collections.synchronizedList(new ArrayList<>()); + private static boolean reset = true; + + public static Handler getProcessHandler(Handler next) { + + if (processHandler == null || reset) { + synchronized (AddonHandlerManager.class) { + if (processHandler == null || reset) { + processHandler = buildHandler(next); + reset = false; + } + } + } + return processHandler; + } + + private static synchronized Handler buildHandler(Handler next) { + // 当没有插件的 handler 的时候,返回原始的 handler + if (handlers.isEmpty()) { + return next; + } + + return HandlerFactory.getHandler(handlers, next); + } + + public static void addHandler(Class c) { + handlers.removeIf(handler -> ClassUtil.getUsefulClass(handler.getClass()).getName().equals(c.getName())); + handlers.add(ClassUtil.newInstance(c)); + resetProcessHandler(); + } + + public static void deleteHandler(Class c) { + handlers.removeIf(handler -> ClassUtil.getUsefulClass(handler.getClass()).getName().equals(c.getName())); + resetProcessHandler(); + } + + private static void resetProcessHandler() { + reset = true; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/handler/AddonHandlerProcesser.java b/jpress-core/src/main/java/io/jpress/core/addon/handler/AddonHandlerProcesser.java index fe03847b12bad1b53c6e09f51f82ea0005c2d4a3..135c8c3ff5fa1b8a52479d2e091c56e474860646 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/handler/AddonHandlerProcesser.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/handler/AddonHandlerProcesser.java @@ -1,36 +1,36 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon.handler; - - -import com.jfinal.handler.Handler; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - - -public class AddonHandlerProcesser extends Handler { - - - @Override - public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { - - Handler processHandler = AddonHandlerManager.getProcessHandler(next); - processHandler.handle(target, request, response, isHandled); - - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon.handler; + + +import com.jfinal.handler.Handler; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +public class AddonHandlerProcesser extends Handler { + + + @Override + public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { + + Handler processHandler = AddonHandlerManager.getProcessHandler(next); + processHandler.handle(target, request, response, isHandled); + + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/interceptor/AddonInterceptorManager.java b/jpress-core/src/main/java/io/jpress/core/addon/interceptor/AddonInterceptorManager.java index 6a276cb9c99bf4090d09a6c63f21cba31118d99e..90e1bec6134c6d5a450514a36c70adfce6a9457f 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/interceptor/AddonInterceptorManager.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/interceptor/AddonInterceptorManager.java @@ -1,54 +1,54 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon.interceptor; - - -import com.jfinal.aop.Interceptor; -import io.jboot.utils.ClassUtil; - -import java.util.*; - -public class AddonInterceptorManager { - - private static Interceptor[] interceptors; - private static Set> interceptorClasses = Collections.synchronizedSet(new HashSet<>()); - - public static Interceptor[] getInterceptors() { - return interceptors; - } - - private static void initInterceptors() { - synchronized (AddonInterceptorManager.class) { - Interceptor[] temp = new Interceptor[interceptorClasses.size()]; - int index = 0; - Iterator> iterator = interceptorClasses.iterator(); - while (iterator.hasNext()) { - temp[index++] = ClassUtil.newInstance(iterator.next()); - } - interceptors = temp; - } - } - - public static void addInterceptor(Class c) { - interceptorClasses.add(c); - initInterceptors(); - } - - public static void deleteInterceptor(Class c) { - interceptorClasses.removeIf(aClass -> Objects.equals(c.getName(),aClass.getName())); - initInterceptors(); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon.interceptor; + + +import com.jfinal.aop.Interceptor; +import io.jboot.utils.ClassUtil; + +import java.util.*; + +public class AddonInterceptorManager { + + private static Interceptor[] interceptors; + private static Set> interceptorClasses = Collections.synchronizedSet(new HashSet<>()); + + public static Interceptor[] getInterceptors() { + return interceptors; + } + + private static void initInterceptors() { + synchronized (AddonInterceptorManager.class) { + Interceptor[] temp = new Interceptor[interceptorClasses.size()]; + int index = 0; + Iterator> iterator = interceptorClasses.iterator(); + while (iterator.hasNext()) { + temp[index++] = ClassUtil.newInstance(iterator.next()); + } + interceptors = temp; + } + } + + public static void addInterceptor(Class c) { + interceptorClasses.add(c); + initInterceptors(); + } + + public static void deleteInterceptor(Class c) { + interceptorClasses.removeIf(aClass -> Objects.equals(c.getName(),aClass.getName())); + initInterceptors(); + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/interceptor/AddonInterceptorProcesser.java b/jpress-core/src/main/java/io/jpress/core/addon/interceptor/AddonInterceptorProcesser.java index 7e5ae595b523b25dcfde15285cbc21a8e5a746b3..51908b6f2a29951f7155f21b9e7e49d92842107d 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/interceptor/AddonInterceptorProcesser.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/interceptor/AddonInterceptorProcesser.java @@ -1,140 +1,140 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon.interceptor; - -import com.jfinal.aop.Interceptor; -import com.jfinal.aop.Invocation; -import com.jfinal.core.Controller; -import io.jboot.Jboot; -import io.jboot.web.fixedinterceptor.FixedInterceptor; - -import java.lang.reflect.Method; - -public class AddonInterceptorProcesser implements FixedInterceptor { - - @Override - public void intercept(Invocation invocation) { - - Interceptor[] interceptors = AddonInterceptorManager.getInterceptors(); - - if (interceptors == null || interceptors.length == 0) { - invocation.invoke(); - } else { - new AddonInvocation(invocation, interceptors).invoke(); - } - } - - - public static class AddonInvocation extends Invocation { - - private Invocation invocation; - private Interceptor[] inters; - - private int index = 0; - - - public AddonInvocation(Invocation invocation, Interceptor[] interceptors) { - this.invocation = invocation; - this.inters = interceptors; - } - - - @Override - public void invoke() { - if (index < inters.length) { - Interceptor interceptor = inters[index++]; - try { - interceptor.intercept(this); - }finally { - if (Jboot.isDevMode()){ - System.out.println("addon interceptor intercepted : " + interceptor); - } - } - - } else if (index++ == inters.length) { - invocation.invoke(); - } - } - - - @Override - public Object getArg(int index) { - return invocation.getArg(index); - } - - @Override - public void setArg(int index, Object value) { - invocation.setArg(index, value); - } - - @Override - public Object[] getArgs() { - return invocation.getArgs(); - } - - @Override - public T getTarget() { - return invocation.getTarget(); - } - - @Override - public Method getMethod() { - return invocation.getMethod(); - } - - @Override - public String getMethodName() { - return invocation.getMethodName(); - } - - @Override - public T getReturnValue() { - return invocation.getReturnValue(); - } - - @Override - public void setReturnValue(Object returnValue) { - invocation.setReturnValue(returnValue); - } - - @Override - public Controller getController() { - return invocation.getController(); - } - - @Override - public String getActionKey() { - return invocation.getActionKey(); - } - - @Override - public String getControllerKey() { - return invocation.getControllerKey(); - } - - @Override - public String getViewPath() { - return invocation.getViewPath(); - } - - @Override - public boolean isActionInvocation() { - return invocation.isActionInvocation(); - } - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon.interceptor; + +import com.jfinal.aop.Interceptor; +import com.jfinal.aop.Invocation; +import com.jfinal.core.Controller; +import io.jboot.Jboot; +import io.jboot.web.fixedinterceptor.FixedInterceptor; + +import java.lang.reflect.Method; + +public class AddonInterceptorProcesser implements FixedInterceptor { + + @Override + public void intercept(Invocation invocation) { + + Interceptor[] interceptors = AddonInterceptorManager.getInterceptors(); + + if (interceptors == null || interceptors.length == 0) { + invocation.invoke(); + } else { + new AddonInvocation(invocation, interceptors).invoke(); + } + } + + + public static class AddonInvocation extends Invocation { + + private Invocation invocation; + private Interceptor[] inters; + + private int index = 0; + + + public AddonInvocation(Invocation invocation, Interceptor[] interceptors) { + this.invocation = invocation; + this.inters = interceptors; + } + + + @Override + public void invoke() { + if (index < inters.length) { + Interceptor interceptor = inters[index++]; + try { + interceptor.intercept(this); + }finally { + if (Jboot.isDevMode()){ + System.out.println("addon interceptor intercepted : " + interceptor); + } + } + + } else if (index++ == inters.length) { + invocation.invoke(); + } + } + + + @Override + public Object getArg(int index) { + return invocation.getArg(index); + } + + @Override + public void setArg(int index, Object value) { + invocation.setArg(index, value); + } + + @Override + public Object[] getArgs() { + return invocation.getArgs(); + } + + @Override + public T getTarget() { + return invocation.getTarget(); + } + + @Override + public Method getMethod() { + return invocation.getMethod(); + } + + @Override + public String getMethodName() { + return invocation.getMethodName(); + } + + @Override + public T getReturnValue() { + return invocation.getReturnValue(); + } + + @Override + public void setReturnValue(Object returnValue) { + invocation.setReturnValue(returnValue); + } + + @Override + public Controller getController() { + return invocation.getController(); + } + + @Override + public String getActionKey() { + return invocation.getActionKey(); + } + + @Override + public String getControllerKey() { + return invocation.getControllerKey(); + } + + @Override + public String getViewPath() { + return invocation.getViewPath(); + } + + @Override + public boolean isActionInvocation() { + return invocation.isActionInvocation(); + } + } + + +} diff --git a/jpress-core/src/main/java/io/jpress/core/addon/template/AddonTemplateEnv.java b/jpress-core/src/main/java/io/jpress/core/addon/template/AddonTemplateEnv.java index f070179571040c4568298e8fc8e58665411b8bdc..0d38c18aed36f0f6c89744f50073802a89dd7b00 100644 --- a/jpress-core/src/main/java/io/jpress/core/addon/template/AddonTemplateEnv.java +++ b/jpress-core/src/main/java/io/jpress/core/addon/template/AddonTemplateEnv.java @@ -1,37 +1,37 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.addon.template; - -import com.jfinal.template.EngineConfig; -import com.jfinal.template.Env; -import com.jfinal.template.stat.ast.Define; - -import java.util.Map; - -/** - * @author michael yang (fuhai999@gmail.com) - * @Date: 2020/2/10 - */ -public class AddonTemplateEnv extends Env { - - public AddonTemplateEnv(EngineConfig engineConfig) { - super(engineConfig); - } - - public Map getFunctionMap() { - return functionMap; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.addon.template; + +import com.jfinal.template.EngineConfig; +import com.jfinal.template.Env; +import com.jfinal.template.stat.ast.Define; + +import java.util.Map; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/2/10 + */ +public class AddonTemplateEnv extends Env { + + public AddonTemplateEnv(EngineConfig engineConfig) { + super(engineConfig); + } + + public Map getFunctionMap() { + return functionMap; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/annotation/AdminPermission.java b/jpress-core/src/main/java/io/jpress/core/annotation/AdminPermission.java index f4c0ba1e49b8ccfa684a555173703e530907ce35..6761a603cebed98cf8183c705e4584e22c7ca672 100644 --- a/jpress-core/src/main/java/io/jpress/core/annotation/AdminPermission.java +++ b/jpress-core/src/main/java/io/jpress/core/annotation/AdminPermission.java @@ -1,30 +1,30 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.annotation; - -import java.lang.annotation.*; - -/** - * AdminPermission - */ -@Inherited -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD}) -public @interface AdminPermission { - - String value(); - +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.annotation; + +import java.lang.annotation.*; + +/** + * AdminPermission + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface AdminPermission { + + String value(); + } \ No newline at end of file diff --git a/jpress-core/src/main/java/io/jpress/core/annotation/NeedUserLogined.java b/jpress-core/src/main/java/io/jpress/core/annotation/NeedUserLogined.java index 48fa7c72de001563122a5ef6b80bb2de0c20e0b7..e9c30c966c3151d1084dd1daded58c67a4656603 100644 --- a/jpress-core/src/main/java/io/jpress/core/annotation/NeedUserLogined.java +++ b/jpress-core/src/main/java/io/jpress/core/annotation/NeedUserLogined.java @@ -1,28 +1,28 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.annotation; - -import java.lang.annotation.*; - -/** - * 用在API上,标识需要用户登录才能正常使用该API - * 一般情况使用在需要获得用户信息的API上,比如评论 - */ -@Inherited -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD}) -public @interface NeedUserLogined { +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.annotation; + +import java.lang.annotation.*; + +/** + * 用在API上,标识需要用户登录才能正常使用该API + * 一般情况使用在需要获得用户信息的API上,比如评论 + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface NeedUserLogined { } \ No newline at end of file diff --git a/jpress-core/src/main/java/io/jpress/core/attachment/AttachmentDownloader.java b/jpress-core/src/main/java/io/jpress/core/attachment/AttachmentDownloader.java index 857b324da97ed00c2b84c2ce63e3bdaaebb25547..d7ce94c6bc89927dc9ce4f1998e335bfae11ad96 100644 --- a/jpress-core/src/main/java/io/jpress/core/attachment/AttachmentDownloader.java +++ b/jpress-core/src/main/java/io/jpress/core/attachment/AttachmentDownloader.java @@ -1,80 +1,80 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.attachment; - -import com.jfinal.kit.LogKit; -import io.jboot.components.http.JbootHttpRequest; -import io.jboot.components.http.JbootHttpResponse; -import io.jboot.utils.HttpUtil; -import io.jboot.utils.NamedThreadPools; -import io.jboot.utils.StrUtil; -import io.jpress.commons.utils.AttachmentUtils; -import io.jpress.model.Attachment; - -import java.io.File; -import java.net.URI; -import java.util.concurrent.ExecutorService; - -/** - * 负责把远程的附件本地化 - */ -public class AttachmentDownloader { - - private static ExecutorService fixedThreadPool = NamedThreadPools.newFixedThreadPool(3, "attachment-download"); - - /** - * 用于下载远程附件,下载成功后 更新 attachment 本身的路径 - * - * @param attachment - */ - public static void download(Attachment attachment) { - fixedThreadPool.execute(() -> { - doDownload(attachment); - }); - } - - private static void doDownload(Attachment attachment) { - - if (attachment.isLocal()) { - return; - } - - String url = attachment.getPath(); - if (StrUtil.isBlank(url)) { - return; - } - - String path = "/attachment" + URI.create(url).getPath(); - - File downloadToFile = AttachmentUtils.file(path); - - JbootHttpRequest request = JbootHttpRequest.create(url); - request.setDownloadFile(downloadToFile); - - JbootHttpResponse response = HttpUtil.handle(request); - if (response.isError()) { - LogKit.error("download attachment error by url:" + url); - return; - } - - attachment.setMimeType(response.getContentType()); - attachment.setPath(path); - attachment.update(); - - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.attachment; + +import com.jfinal.kit.LogKit; +import io.jboot.components.http.JbootHttpRequest; +import io.jboot.components.http.JbootHttpResponse; +import io.jboot.utils.HttpUtil; +import io.jboot.utils.NamedThreadPools; +import io.jboot.utils.StrUtil; +import io.jpress.commons.utils.AttachmentUtils; +import io.jpress.model.Attachment; + +import java.io.File; +import java.net.URI; +import java.util.concurrent.ExecutorService; + +/** + * 负责把远程的附件本地化 + */ +public class AttachmentDownloader { + + private static ExecutorService fixedThreadPool = NamedThreadPools.newFixedThreadPool(3, "attachment-download"); + + /** + * 用于下载远程附件,下载成功后 更新 attachment 本身的路径 + * + * @param attachment + */ + public static void download(Attachment attachment) { + fixedThreadPool.execute(() -> { + doDownload(attachment); + }); + } + + private static void doDownload(Attachment attachment) { + + if (attachment.isLocal()) { + return; + } + + String url = attachment.getPath(); + if (StrUtil.isBlank(url)) { + return; + } + + String path = "/attachment" + URI.create(url).getPath(); + + File downloadToFile = AttachmentUtils.file(path); + + JbootHttpRequest request = JbootHttpRequest.create(url); + request.setDownloadFile(downloadToFile); + + JbootHttpResponse response = HttpUtil.handle(request); + if (response.isError()) { + LogKit.error("download attachment error by url:" + url); + return; + } + + attachment.setMimeType(response.getContentType()); + attachment.setPath(path); + attachment.update(); + + } + + +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/BaseProductInfoQuerier.java b/jpress-core/src/main/java/io/jpress/core/finance/BaseProductInfoQuerier.java index c1dc9f896faeee5169135c4ff6904d03287d8312..918b40f42ddfda813d7f35983b370ff0d0b268ed 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/BaseProductInfoQuerier.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/BaseProductInfoQuerier.java @@ -1,48 +1,48 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.finance; - -import io.jpress.model.UserCart; - -import java.math.BigDecimal; - -/** - * @author michael yang (fuhai999@gmail.com) - * @Date: 2019/11/27 - */ -public class BaseProductInfoQuerier implements ProductInfoQuerier { - - - @Override - public BigDecimal queryDistAmount(UserCart userCart, Long productId, String productSpec, Long payerId, Long distUserId) { - return null; - } - - @Override - public BigDecimal querySalePrice(UserCart userCart, Long productId, String productSpec, Long payerId) { - return null; - } - - @Override - public boolean queryStatusNormal(UserCart userCart, Long productId, String productSpec, Long payerId) { - return true; - } - - @Override - public Long queryStockAmount(UserCart userCart, Long productId, String productSpec) { - return null; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.finance; + +import io.jpress.model.UserCart; + +import java.math.BigDecimal; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2019/11/27 + */ +public class BaseProductInfoQuerier implements ProductInfoQuerier { + + + @Override + public BigDecimal queryDistAmount(UserCart userCart, Long productId, String productSpec, Long payerId, Long distUserId) { + return null; + } + + @Override + public BigDecimal querySalePrice(UserCart userCart, Long productId, String productSpec, Long payerId) { + return null; + } + + @Override + public boolean queryStatusNormal(UserCart userCart, Long productId, String productSpec, Long payerId) { + return true; + } + + @Override + public Long queryStockAmount(UserCart userCart, Long productId, String productSpec) { + return null; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/OrderItemStatusChangeListener.java b/jpress-core/src/main/java/io/jpress/core/finance/OrderItemStatusChangeListener.java index 590f392d2d1e7ef525c8f108bba07458b0c6a6ab..492e743a912515aa0ec3a096e8607a1465f5b88b 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/OrderItemStatusChangeListener.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/OrderItemStatusChangeListener.java @@ -1,25 +1,25 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.finance; - -import io.jpress.model.UserOrderItem; - - -public interface OrderItemStatusChangeListener { - - public void onStatusChanged(UserOrderItem orderItem); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.finance; + +import io.jpress.model.UserOrderItem; + + +public interface OrderItemStatusChangeListener { + + public void onStatusChanged(UserOrderItem orderItem); + +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/OrderManager.java b/jpress-core/src/main/java/io/jpress/core/finance/OrderManager.java index a14fd746be229750fb8c186881e2db2c546d289f..b507fe913d8987ffa4aff7fb9ca04f8bdf238610 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/OrderManager.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/OrderManager.java @@ -1,112 +1,112 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.finance; - - -import com.jfinal.aop.Aop; -import com.jfinal.log.Log; -import io.jpress.model.UserOrder; -import io.jpress.model.UserOrderItem; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * @author michael yang - */ -public class OrderManager { - - private static final Log LOG = Log.getLog(OrderManager.class); - - public static final OrderManager me = new OrderManager(); - - private OrderManager() { - } - - public static final OrderManager me() { - return me; - } - - private List orderItemStatusChangeListeners; - private List orderStatusChangeListeners; - - - public List getOrderItemStatusChangeListeners() { - return orderItemStatusChangeListeners; - } - - - public void setOrderItemStatusChangeListeners(List orderItemStatusChangeListeners) { - this.orderItemStatusChangeListeners = orderItemStatusChangeListeners; - } - - - public void addOrderItemStatusChangeListener(OrderItemStatusChangeListener listener) { - if (orderItemStatusChangeListeners == null) { - synchronized (OrderManager.class) { - orderItemStatusChangeListeners = Collections.synchronizedList(new ArrayList<>()); - } - } - orderItemStatusChangeListeners.add(Aop.inject(listener)); - } - - - public List getOrderStatusChangeListeners() { - return orderStatusChangeListeners; - } - - - public void setOrderStatusChangeListeners(List orderItemStatusChangeListeners) { - this.orderStatusChangeListeners = orderItemStatusChangeListeners; - } - - - public void addOrderStatusChangeListener(OrderStatusChangeListener listener) { - if (orderStatusChangeListeners == null) { - synchronized (OrderManager.class) { - orderStatusChangeListeners = Collections.synchronizedList(new ArrayList<>()); - } - } - orderStatusChangeListeners.add(Aop.inject(listener)); - } - - - public void notifyItemStatusChanged(UserOrderItem userOrderItem) { - if (orderItemStatusChangeListeners != null && userOrderItem != null) { - for (OrderItemStatusChangeListener listener : orderItemStatusChangeListeners) { - try { - listener.onStatusChanged(userOrderItem); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - } - } - } - - public void notifyOrderStatusChanged(UserOrder order) { - if (orderStatusChangeListeners != null && order != null) { - for (OrderStatusChangeListener listener : orderStatusChangeListeners) { - try { - listener.onStatusChanged(order); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - } - } - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.finance; + + +import com.jfinal.aop.Aop; +import com.jfinal.log.Log; +import io.jpress.model.UserOrder; +import io.jpress.model.UserOrderItem; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author michael yang + */ +public class OrderManager { + + private static final Log LOG = Log.getLog(OrderManager.class); + + public static final OrderManager me = new OrderManager(); + + private OrderManager() { + } + + public static final OrderManager me() { + return me; + } + + private List orderItemStatusChangeListeners; + private List orderStatusChangeListeners; + + + public List getOrderItemStatusChangeListeners() { + return orderItemStatusChangeListeners; + } + + + public void setOrderItemStatusChangeListeners(List orderItemStatusChangeListeners) { + this.orderItemStatusChangeListeners = orderItemStatusChangeListeners; + } + + + public void addOrderItemStatusChangeListener(OrderItemStatusChangeListener listener) { + if (orderItemStatusChangeListeners == null) { + synchronized (OrderManager.class) { + orderItemStatusChangeListeners = Collections.synchronizedList(new ArrayList<>()); + } + } + orderItemStatusChangeListeners.add(Aop.inject(listener)); + } + + + public List getOrderStatusChangeListeners() { + return orderStatusChangeListeners; + } + + + public void setOrderStatusChangeListeners(List orderItemStatusChangeListeners) { + this.orderStatusChangeListeners = orderItemStatusChangeListeners; + } + + + public void addOrderStatusChangeListener(OrderStatusChangeListener listener) { + if (orderStatusChangeListeners == null) { + synchronized (OrderManager.class) { + orderStatusChangeListeners = Collections.synchronizedList(new ArrayList<>()); + } + } + orderStatusChangeListeners.add(Aop.inject(listener)); + } + + + public void notifyItemStatusChanged(UserOrderItem userOrderItem) { + if (orderItemStatusChangeListeners != null && userOrderItem != null) { + for (OrderItemStatusChangeListener listener : orderItemStatusChangeListeners) { + try { + listener.onStatusChanged(userOrderItem); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + } + } + } + + public void notifyOrderStatusChanged(UserOrder order) { + if (orderStatusChangeListeners != null && order != null) { + for (OrderStatusChangeListener listener : orderStatusChangeListeners) { + try { + listener.onStatusChanged(order); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + } + } + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/OrderStatusChangeListener.java b/jpress-core/src/main/java/io/jpress/core/finance/OrderStatusChangeListener.java index d3aa912a012f306c45dca3a794bb2fbcac4244ba..e2d47a6c1c2f259decda313dde21a8df253f42ed 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/OrderStatusChangeListener.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/OrderStatusChangeListener.java @@ -1,25 +1,25 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.finance; - -import io.jpress.model.UserOrder; - - -public interface OrderStatusChangeListener { - - public void onStatusChanged(UserOrder order); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.finance; + +import io.jpress.model.UserOrder; + + +public interface OrderStatusChangeListener { + + public void onStatusChanged(UserOrder order); + +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/PaymentManager.java b/jpress-core/src/main/java/io/jpress/core/finance/PaymentManager.java index e5fa4d7623808974e6e160d373b571c2f65a4dde..df75675aed8d29547499f65d28979c039b7c28ef 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/PaymentManager.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/PaymentManager.java @@ -1,70 +1,70 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.finance; - - -import com.jfinal.aop.Aop; -import com.jfinal.log.Log; -import io.jpress.model.PaymentRecord; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class PaymentManager { - - private static final Log LOG = Log.getLog(PaymentManager.class); - - public static final PaymentManager me = new PaymentManager(); - - private PaymentManager() { - } - - public static final PaymentManager me() { - return me; - } - - private List listeners; - - public List getListeners() { - return listeners; - } - - public void setListeners(List listeners) { - this.listeners = listeners; - } - - public void addListener(PaymentSuccessListener listener) { - if (listeners == null) { - synchronized (PaymentManager.class) { - listeners = Collections.synchronizedList(new ArrayList<>()); - } - } - listeners.add(Aop.inject(listener)); - } - - public void notifySuccess(PaymentRecord payment) { - if (listeners != null && payment != null && payment.isPaySuccess()) { - for (PaymentSuccessListener listener : listeners) { - try { - listener.onSuccess(payment); - } catch (Exception ex) { - LOG.error(ex.toString(), ex); - } - } - } - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.finance; + + +import com.jfinal.aop.Aop; +import com.jfinal.log.Log; +import io.jpress.model.PaymentRecord; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class PaymentManager { + + private static final Log LOG = Log.getLog(PaymentManager.class); + + public static final PaymentManager me = new PaymentManager(); + + private PaymentManager() { + } + + public static final PaymentManager me() { + return me; + } + + private List listeners; + + public List getListeners() { + return listeners; + } + + public void setListeners(List listeners) { + this.listeners = listeners; + } + + public void addListener(PaymentSuccessListener listener) { + if (listeners == null) { + synchronized (PaymentManager.class) { + listeners = Collections.synchronizedList(new ArrayList<>()); + } + } + listeners.add(Aop.inject(listener)); + } + + public void notifySuccess(PaymentRecord payment) { + if (listeners != null && payment != null && payment.isPaySuccess()) { + for (PaymentSuccessListener listener : listeners) { + try { + listener.onSuccess(payment); + } catch (Exception ex) { + LOG.error(ex.toString(), ex); + } + } + } + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/PaymentSuccessListener.java b/jpress-core/src/main/java/io/jpress/core/finance/PaymentSuccessListener.java index 526aba68da831d8f8e45b516636742375d090f0a..b90d8c04dd19e4493ffabb6bbc6f79f9ab8a5592 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/PaymentSuccessListener.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/PaymentSuccessListener.java @@ -1,25 +1,25 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.finance; - -import io.jpress.model.PaymentRecord; - - -public interface PaymentSuccessListener { - - public void onSuccess(PaymentRecord payment); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.finance; + +import io.jpress.model.PaymentRecord; + + +public interface PaymentSuccessListener { + + public void onSuccess(PaymentRecord payment); + +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/ProductInfoQuerier.java b/jpress-core/src/main/java/io/jpress/core/finance/ProductInfoQuerier.java index 30b45593a3a8c15c6b2d35ff7b18482cd6fb7e89..da9d6a7f6dbeb5d91847a01a4ac8f9a0533e81dc 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/ProductInfoQuerier.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/ProductInfoQuerier.java @@ -1,69 +1,69 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.finance; - -import io.jpress.model.UserCart; - -import java.math.BigDecimal; - - -public interface ProductInfoQuerier { - - /** - * 查询产品的销售分成金额 - * - * @param userCart - * @param payerId - * @return - */ - public BigDecimal queryDistAmount(UserCart userCart, Long productId, String productSpec, Long payerId, Long distUserId); - - - /** - * 查询该商品的销售价格 - * - * @param userCart - * @param productId - * @param productSpec - * @param payerId - * @return - */ - public BigDecimal querySalePrice(UserCart userCart, Long productId, String productSpec, Long payerId); - - - /** - * 查询该商品是否正常销售 - * - * @param userCart - * @param productId - * @param productSpec - * @param payerId - * @return - */ - public boolean queryStatusNormal(UserCart userCart, Long productId, String productSpec, Long payerId); - - - /** - * 查询商品库存数量 - * - * @param userCart - * @param productId - * @param productSpec - * @return - */ - public Long queryStockAmount(UserCart userCart, Long productId, String productSpec); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.finance; + +import io.jpress.model.UserCart; + +import java.math.BigDecimal; + + +public interface ProductInfoQuerier { + + /** + * 查询产品的销售分成金额 + * + * @param userCart + * @param payerId + * @return + */ + public BigDecimal queryDistAmount(UserCart userCart, Long productId, String productSpec, Long payerId, Long distUserId); + + + /** + * 查询该商品的销售价格 + * + * @param userCart + * @param productId + * @param productSpec + * @param payerId + * @return + */ + public BigDecimal querySalePrice(UserCart userCart, Long productId, String productSpec, Long payerId); + + + /** + * 查询该商品是否正常销售 + * + * @param userCart + * @param productId + * @param productSpec + * @param payerId + * @return + */ + public boolean queryStatusNormal(UserCart userCart, Long productId, String productSpec, Long payerId); + + + /** + * 查询商品库存数量 + * + * @param userCart + * @param productId + * @param productSpec + * @return + */ + public Long queryStockAmount(UserCart userCart, Long productId, String productSpec); + +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/ProductManager.java b/jpress-core/src/main/java/io/jpress/core/finance/ProductManager.java index d072a5fffe09de58ee531aac0bcaa17dcb508339..208b4d79947985a88faff8f9ed43db2c6618141f 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/ProductManager.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/ProductManager.java @@ -1,181 +1,181 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.finance; - - -import com.jfinal.aop.Aop; -import io.jboot.utils.StrUtil; -import io.jpress.model.UserCart; -import io.jpress.model.UserOrderItem; - -import java.math.BigDecimal; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -public class ProductManager { - - private static final ProductManager me = new ProductManager(); - - private ProductManager() { - } - - public static final ProductManager me() { - return me; - } - - private Map productInfoQuerierMap = new ConcurrentHashMap<>(); - private Map productOptionsRenderMap = new ConcurrentHashMap<>(); - - - public Map getProductInfoQuerierMap() { - return productInfoQuerierMap; - } - - public void setProductInfoQuerierMap(Map productInfoQuerierMap) { - this.productInfoQuerierMap = productInfoQuerierMap; - } - - public void registerQuerier(String forProductType, ProductInfoQuerier querier) { - productInfoQuerierMap.put(forProductType, Aop.inject(querier)); - } - - public void unregisterQuerier(String forProductType) { - productInfoQuerierMap.remove(forProductType); - } - - public void registerOptionsRender(String forProductType, ProductOptionsRender render) { - productOptionsRenderMap.put(forProductType, Aop.inject(render)); - } - - public void unregisterOptionsRender(String forProductType) { - productOptionsRenderMap.remove(forProductType); - } - - public Map renderProductOptions(UserCart userCart) { - if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { - return null; - } - ProductOptionsRender render = productOptionsRenderMap.get(userCart.getProductType()); - if (render == null) { - return null; - } - return render.doRenderUserCartOptions(userCart); - } - - public Map renderProductOptions(UserOrderItem userOrderItem) { - if (userOrderItem == null || StrUtil.isBlank(userOrderItem.getProductType())) { - return null; - } - ProductOptionsRender render = productOptionsRenderMap.get(userOrderItem.getProductType()); - if (render == null) { - return null; - } - return render.doRenderUserCartOptions(userOrderItem); - } - - /** - * 查询产品的分销金额 - * - * @param userCart - * @param payerId - * @param distUserId - * @return - */ - public BigDecimal queryDistAmount(UserCart userCart, Long productId, String productSpec, Long payerId, Long distUserId) { - if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { - return BigDecimal.ZERO; - } - ProductInfoQuerier querier = productInfoQuerierMap.get(userCart.getProductType()); - if (querier == null) { - return BigDecimal.ZERO; - } - - if (Objects.equals(distUserId, payerId)) { - return BigDecimal.ZERO; - } - - BigDecimal distAmount = querier.queryDistAmount(userCart, productId, productSpec, payerId, distUserId); - return distAmount == null || distAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : distAmount; - } - - - /** - * 查询产品 - * - * @param userCart - * @param productId - * @param productSpec - * @param payerId - * @return - */ - public boolean queryStatusNormal(UserCart userCart, Long productId, String productSpec, Long payerId) { - if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { - return true; - } - - ProductInfoQuerier querier = productInfoQuerierMap.get(userCart.getProductType()); - //没有注册 querier,说明该商品任何时候都可以被购买 - if (querier == null) { - return true; - } - - return querier.queryStatusNormal(userCart, productId, productSpec, payerId); - } - - - /** - * 查询产品的价格,当一个商品被添加到购物车后,可能还会变动价格(或者有会员价等) - * - * @param userCart - * @param productId - * @param productSpec - * @param payerId - * @return - */ - public BigDecimal querySalePrice(UserCart userCart, Long productId, String productSpec, Long payerId) { - if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { - return null; - } - ProductInfoQuerier querier = productInfoQuerierMap.get(userCart.getProductType()); - if (querier == null) { - return null; - } - - return querier.querySalePrice(userCart, productId, productSpec, payerId); - } - - - /** - * 查询产品的库存,当库存不足的时候不让购买 - * - * @param userCart - * @param productId - * @param productSpec - * @return - */ - public Long queryStockAmount(UserCart userCart, Long productId, String productSpec) { - if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { - return null; - } - ProductInfoQuerier querier = productInfoQuerierMap.get(userCart.getProductType()); - if (querier == null) { - return null; - } - - return querier.queryStockAmount(userCart, productId, productSpec); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.finance; + + +import com.jfinal.aop.Aop; +import io.jboot.utils.StrUtil; +import io.jpress.model.UserCart; +import io.jpress.model.UserOrderItem; + +import java.math.BigDecimal; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +public class ProductManager { + + private static final ProductManager me = new ProductManager(); + + private ProductManager() { + } + + public static final ProductManager me() { + return me; + } + + private Map productInfoQuerierMap = new ConcurrentHashMap<>(); + private Map productOptionsRenderMap = new ConcurrentHashMap<>(); + + + public Map getProductInfoQuerierMap() { + return productInfoQuerierMap; + } + + public void setProductInfoQuerierMap(Map productInfoQuerierMap) { + this.productInfoQuerierMap = productInfoQuerierMap; + } + + public void registerQuerier(String forProductType, ProductInfoQuerier querier) { + productInfoQuerierMap.put(forProductType, Aop.inject(querier)); + } + + public void unregisterQuerier(String forProductType) { + productInfoQuerierMap.remove(forProductType); + } + + public void registerOptionsRender(String forProductType, ProductOptionsRender render) { + productOptionsRenderMap.put(forProductType, Aop.inject(render)); + } + + public void unregisterOptionsRender(String forProductType) { + productOptionsRenderMap.remove(forProductType); + } + + public Map renderProductOptions(UserCart userCart) { + if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { + return null; + } + ProductOptionsRender render = productOptionsRenderMap.get(userCart.getProductType()); + if (render == null) { + return null; + } + return render.doRenderUserCartOptions(userCart); + } + + public Map renderProductOptions(UserOrderItem userOrderItem) { + if (userOrderItem == null || StrUtil.isBlank(userOrderItem.getProductType())) { + return null; + } + ProductOptionsRender render = productOptionsRenderMap.get(userOrderItem.getProductType()); + if (render == null) { + return null; + } + return render.doRenderUserCartOptions(userOrderItem); + } + + /** + * 查询产品的分销金额 + * + * @param userCart + * @param payerId + * @param distUserId + * @return + */ + public BigDecimal queryDistAmount(UserCart userCart, Long productId, String productSpec, Long payerId, Long distUserId) { + if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { + return BigDecimal.ZERO; + } + ProductInfoQuerier querier = productInfoQuerierMap.get(userCart.getProductType()); + if (querier == null) { + return BigDecimal.ZERO; + } + + if (Objects.equals(distUserId, payerId)) { + return BigDecimal.ZERO; + } + + BigDecimal distAmount = querier.queryDistAmount(userCart, productId, productSpec, payerId, distUserId); + return distAmount == null || distAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : distAmount; + } + + + /** + * 查询产品 + * + * @param userCart + * @param productId + * @param productSpec + * @param payerId + * @return + */ + public boolean queryStatusNormal(UserCart userCart, Long productId, String productSpec, Long payerId) { + if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { + return true; + } + + ProductInfoQuerier querier = productInfoQuerierMap.get(userCart.getProductType()); + //没有注册 querier,说明该商品任何时候都可以被购买 + if (querier == null) { + return true; + } + + return querier.queryStatusNormal(userCart, productId, productSpec, payerId); + } + + + /** + * 查询产品的价格,当一个商品被添加到购物车后,可能还会变动价格(或者有会员价等) + * + * @param userCart + * @param productId + * @param productSpec + * @param payerId + * @return + */ + public BigDecimal querySalePrice(UserCart userCart, Long productId, String productSpec, Long payerId) { + if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { + return null; + } + ProductInfoQuerier querier = productInfoQuerierMap.get(userCart.getProductType()); + if (querier == null) { + return null; + } + + return querier.querySalePrice(userCart, productId, productSpec, payerId); + } + + + /** + * 查询产品的库存,当库存不足的时候不让购买 + * + * @param userCart + * @param productId + * @param productSpec + * @return + */ + public Long queryStockAmount(UserCart userCart, Long productId, String productSpec) { + if (userCart == null || StrUtil.isBlank(userCart.getProductType())) { + return null; + } + ProductInfoQuerier querier = productInfoQuerierMap.get(userCart.getProductType()); + if (querier == null) { + return null; + } + + return querier.queryStockAmount(userCart, productId, productSpec); + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/finance/ProductOptionsRender.java b/jpress-core/src/main/java/io/jpress/core/finance/ProductOptionsRender.java index 2f02d82738e50458642694136975db2d3c68e6c7..ebe0535339c1434722055377ad0f2bc4881193cb 100644 --- a/jpress-core/src/main/java/io/jpress/core/finance/ProductOptionsRender.java +++ b/jpress-core/src/main/java/io/jpress/core/finance/ProductOptionsRender.java @@ -1,17 +1,17 @@ -package io.jpress.core.finance; - -import io.jpress.model.UserCart; -import io.jpress.model.UserOrderItem; - -import java.util.Map; - -/** - * @author michael yang (fuhai999@gmail.com) - * @Date: 2020/2/14 - */ -public interface ProductOptionsRender { - - public Map doRenderUserCartOptions(UserCart userCart); - - public Map doRenderUserCartOptions(UserOrderItem userOrderItem); -} +package io.jpress.core.finance; + +import io.jpress.model.UserCart; +import io.jpress.model.UserOrderItem; + +import java.util.Map; + +/** + * @author michael yang (fuhai999@gmail.com) + * @Date: 2020/2/14 + */ +public interface ProductOptionsRender { + + public Map doRenderUserCartOptions(UserCart userCart); + + public Map doRenderUserCartOptions(UserOrderItem userOrderItem); +} diff --git a/jpress-core/src/main/java/io/jpress/core/install/Consts.java b/jpress-core/src/main/java/io/jpress/core/install/Consts.java index 5c447c26ab6e4fb9898b2bc98d0f429f6e398773..b491f572d2d4a5e16c94fb91946d376b5fd799c6 100644 --- a/jpress-core/src/main/java/io/jpress/core/install/Consts.java +++ b/jpress-core/src/main/java/io/jpress/core/install/Consts.java @@ -1,39 +1,39 @@ -/** - * Copyright (c) 2015-2019, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.apache.org/licenses/LICENSE-2.0 - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.install; - - -import com.google.common.collect.Lists; - -import java.util.List; - -class Consts { - - public static List V2_TABLES = Lists.newArrayList("article", "article_category", "article_category_mapping", "article_comment" - , "attachment", "menu", "option", "payment_record", "permission", "role", "role_permission_mapping" - , "single_page" - , "user", "user_role_mapping", "utm", "wechat_menu", "wechat_reply"); - - - public static List V3_TABLES = Lists.newArrayList("article", "article_category", "article_category_mapping", "article_comment" - , "attachment", "coupon", "coupon_code", "coupon_product", "coupon_used_record", "member", "member_dist_amount" - , "member_group", "member_joined_record", "member_price", "menu", "option", "payment_record", "permission", "product" - , "product_category", "product_category_mapping", "product_comment", "product_image", "role", "role_permission_mapping" - , "single_page", "single_page_comment" - , "user", "user_address", "user_amount", "user_amount_payout", "user_amount_statement", "user_cart", "user_favorite", "user_openid" - , "user_order", "user_order_delivery", "user_order_invoice", "user_order_item", "user_role_mapping", "user_tag", "user_tag_mapping" - , "utm", "wechat_menu", "wechat_reply"); -} +/** + * Copyright (c) 2015-2019, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.install; + + +import com.google.common.collect.Lists; + +import java.util.List; + +class Consts { + + public static List V2_TABLES = Lists.newArrayList("article", "article_category", "article_category_mapping", "article_comment" + , "attachment", "menu", "option", "payment_record", "permission", "role", "role_permission_mapping" + , "single_page" + , "user", "user_role_mapping", "utm", "wechat_menu", "wechat_reply"); + + + public static List V3_TABLES = Lists.newArrayList("article", "article_category", "article_category_mapping", "article_comment" + , "attachment", "coupon", "coupon_code", "coupon_product", "coupon_used_record", "member", "member_dist_amount" + , "member_group", "member_joined_record", "member_price", "menu", "option", "payment_record", "permission", "product" + , "product_category", "product_category_mapping", "product_comment", "product_image", "role", "role_permission_mapping" + , "single_page", "single_page_comment" + , "user", "user_address", "user_amount", "user_amount_payout", "user_amount_statement", "user_cart", "user_favorite", "user_openid" + , "user_order", "user_order_delivery", "user_order_invoice", "user_order_item", "user_role_mapping", "user_tag", "user_tag_mapping" + , "utm", "wechat_menu", "wechat_reply"); +} diff --git a/jpress-core/src/main/java/io/jpress/core/install/DbExecuter.java b/jpress-core/src/main/java/io/jpress/core/install/DbExecuter.java index 8d6e5a3ed5726f9d0e1a5b0cfab31358761822ae..c62f3623162a620e189a5c48e09a8fc1a44a04e4 100644 --- a/jpress-core/src/main/java/io/jpress/core/install/DbExecuter.java +++ b/jpress-core/src/main/java/io/jpress/core/install/DbExecuter.java @@ -1,168 +1,168 @@ -/** - * Copyright (c) 2015-2019, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.apache.org/licenses/LICENSE-2.0 - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.install; - - -import io.jboot.db.datasource.DataSourceBuilder; -import io.jboot.db.datasource.DataSourceConfig; -import io.jboot.exception.JbootException; -import io.jboot.utils.StrUtil; -import io.jpress.commons.utils.CommonsUtils; - -import javax.sql.DataSource; -import java.sql.*; -import java.util.ArrayList; -import java.util.List; - -public class DbExecuter { - - private String dbName; - private String dbUser; - private String dbPassword; - private int dbHostPort; - private String jdbcUrl; - - - private DataSource dataSource; - private DataSourceConfig dataSourceConfig; - - public DbExecuter(DataSource dataSource) { - this.dataSource = dataSource; - } - - - public DbExecuter(String dbName, String dbUser, String dbPassword, String dbHost, int dbHostPort) { - this.dbName = dbName; - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.dbHostPort = dbHostPort; - - this.jdbcUrl = "jdbc:mysql://" + dbHost + ":" + dbHostPort + "/" + dbName + "?" - + "useSSL=false&" - + "characterEncoding=utf8&" - + "zeroDateTimeBehavior=convertToNull"; - - this.dataSourceConfig = new DataSourceConfig(); - this.dataSourceConfig.setUrl(this.jdbcUrl); - this.dataSourceConfig.setUser(dbUser); - this.dataSourceConfig.setPassword(dbPassword); - - this.dataSource = new DataSourceBuilder(this.dataSourceConfig).build(); - - } - - - public List queryTables() { - try { - return query("show tables;"); - } catch (SQLException e) { - e.printStackTrace(); - } - return null; - } - - - public void executeSql(String batchSql) throws SQLException { - Connection conn = getConnection(); - Statement pst = null; - try { - pst = conn.createStatement(); - if (StrUtil.isBlank(batchSql)) { - throw new SQLException("sql is null or empty"); - } - if (batchSql.contains(";")) { - String[] sqls = batchSql.split(";"); - for (String sql : sqls) { - if (StrUtil.isNotBlank(sql)) { - pst.addBatch(sql); - } - } - } else { - pst.addBatch(batchSql); - } - } finally { - pst.executeBatch(); - CommonsUtils.quietlyClose(pst, conn); - } - } - - - public List query(String sql) throws SQLException { - List result = new ArrayList(); - PreparedStatement pst = null; - ResultSet rs = null; - Connection conn = getConnection(); - try { - pst = conn.prepareStatement(sql); - rs = pst.executeQuery(); - int colAmount = rs.getMetaData().getColumnCount(); - if (colAmount > 1) { - while (rs.next()) { - Object[] temp = new Object[colAmount]; - for (int i = 0; i < colAmount; i++) { - temp[i] = rs.getObject(i + 1); - } - result.add(temp); - } - } else if (colAmount == 1) { - while (rs.next()) { - result.add(rs.getObject(1)); - } - } - } finally { - CommonsUtils.quietlyClose(rs, pst, conn); - } - return result; - } - - - private Connection getConnection() { - try { - return dataSource.getConnection(); - } catch (SQLException e) { - throw new JbootException(e); - } - } - - - public DataSource getDataSource() { - return dataSource; - } - - public DataSourceConfig getDataSourceConfig() { - return dataSourceConfig; - } - - public String getDbName() { - return dbName; - } - - public String getDbUser() { - return dbUser; - } - - public String getDbPassword() { - return dbPassword; - } - - public int getDbHostPort() { - return dbHostPort; - } - - public String getJdbcUrl() { - return jdbcUrl; - } -} +/** + * Copyright (c) 2015-2019, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.apache.org/licenses/LICENSE-2.0 + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.install; + + +import io.jboot.db.datasource.DataSourceBuilder; +import io.jboot.db.datasource.DataSourceConfig; +import io.jboot.exception.JbootException; +import io.jboot.utils.StrUtil; +import io.jpress.commons.utils.CommonsUtils; + +import javax.sql.DataSource; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class DbExecuter { + + private String dbName; + private String dbUser; + private String dbPassword; + private int dbHostPort; + private String jdbcUrl; + + + private DataSource dataSource; + private DataSourceConfig dataSourceConfig; + + public DbExecuter(DataSource dataSource) { + this.dataSource = dataSource; + } + + + public DbExecuter(String dbName, String dbUser, String dbPassword, String dbHost, int dbHostPort) { + this.dbName = dbName; + this.dbUser = dbUser; + this.dbPassword = dbPassword; + this.dbHostPort = dbHostPort; + + this.jdbcUrl = "jdbc:mysql://" + dbHost + ":" + dbHostPort + "/" + dbName + "?" + + "useSSL=false&" + + "characterEncoding=utf8&" + + "zeroDateTimeBehavior=convertToNull"; + + this.dataSourceConfig = new DataSourceConfig(); + this.dataSourceConfig.setUrl(this.jdbcUrl); + this.dataSourceConfig.setUser(dbUser); + this.dataSourceConfig.setPassword(dbPassword); + + this.dataSource = new DataSourceBuilder(this.dataSourceConfig).build(); + + } + + + public List queryTables() { + try { + return query("show tables;"); + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + + public void executeSql(String batchSql) throws SQLException { + Connection conn = getConnection(); + Statement pst = null; + try { + pst = conn.createStatement(); + if (StrUtil.isBlank(batchSql)) { + throw new SQLException("sql is null or empty"); + } + if (batchSql.contains(";")) { + String[] sqls = batchSql.split(";"); + for (String sql : sqls) { + if (StrUtil.isNotBlank(sql)) { + pst.addBatch(sql); + } + } + } else { + pst.addBatch(batchSql); + } + } finally { + pst.executeBatch(); + CommonsUtils.quietlyClose(pst, conn); + } + } + + + public List query(String sql) throws SQLException { + List result = new ArrayList(); + PreparedStatement pst = null; + ResultSet rs = null; + Connection conn = getConnection(); + try { + pst = conn.prepareStatement(sql); + rs = pst.executeQuery(); + int colAmount = rs.getMetaData().getColumnCount(); + if (colAmount > 1) { + while (rs.next()) { + Object[] temp = new Object[colAmount]; + for (int i = 0; i < colAmount; i++) { + temp[i] = rs.getObject(i + 1); + } + result.add(temp); + } + } else if (colAmount == 1) { + while (rs.next()) { + result.add(rs.getObject(1)); + } + } + } finally { + CommonsUtils.quietlyClose(rs, pst, conn); + } + return result; + } + + + private Connection getConnection() { + try { + return dataSource.getConnection(); + } catch (SQLException e) { + throw new JbootException(e); + } + } + + + public DataSource getDataSource() { + return dataSource; + } + + public DataSourceConfig getDataSourceConfig() { + return dataSourceConfig; + } + + public String getDbName() { + return dbName; + } + + public String getDbUser() { + return dbUser; + } + + public String getDbPassword() { + return dbPassword; + } + + public int getDbHostPort() { + return dbHostPort; + } + + public String getJdbcUrl() { + return jdbcUrl; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/install/InstallHandler.java b/jpress-core/src/main/java/io/jpress/core/install/InstallHandler.java index 39d0f1ec3afe13cf2a5fe412aff59926ba5d1ced..9a0a2695ce80ea0ced5aef3fb84706face75872c 100644 --- a/jpress-core/src/main/java/io/jpress/core/install/InstallHandler.java +++ b/jpress-core/src/main/java/io/jpress/core/install/InstallHandler.java @@ -1,48 +1,48 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.install; - -import com.jfinal.handler.Handler; -import com.jfinal.kit.HandlerKit; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - - -public class InstallHandler extends Handler { - - @Override - public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { - - if (Installer.isInstalled()) { - next.handle(target, request, response, isHandled); - return; - } - - if (target.indexOf('.') != -1) { - return; - } - - if (!target.startsWith("/install")) { - HandlerKit.redirect(request.getContextPath() + "/install",request,response,isHandled); - } else { - next.handle(target, request, response, isHandled); - } - - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.install; + +import com.jfinal.handler.Handler; +import com.jfinal.kit.HandlerKit; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +public class InstallHandler extends Handler { + + @Override + public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { + + if (Installer.isInstalled()) { + next.handle(target, request, response, isHandled); + return; + } + + if (target.indexOf('.') != -1) { + return; + } + + if (!target.startsWith("/install")) { + HandlerKit.redirect(request.getContextPath() + "/install",request,response,isHandled); + } else { + next.handle(target, request, response, isHandled); + } + + } + + +} diff --git a/jpress-core/src/main/java/io/jpress/core/install/InstallManager.java b/jpress-core/src/main/java/io/jpress/core/install/InstallManager.java index cc1999c96a66e5051b95ec60150e6fa05a983d95..1297cd9b1340c46ee12f504814eebd571249c3ed 100644 --- a/jpress-core/src/main/java/io/jpress/core/install/InstallManager.java +++ b/jpress-core/src/main/java/io/jpress/core/install/InstallManager.java @@ -1,127 +1,127 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.install; - -import com.jfinal.kit.PathKit; -import io.jboot.db.datasource.DataSourceConfig; -import io.jboot.utils.ArrayUtil; -import io.jboot.utils.FileUtil; - -import java.io.File; -import java.sql.SQLException; -import java.util.List; - -/** - * @author yang fuhai - */ -public class InstallManager { - - - private DbExecuter dbExecuter; - - private boolean dbExist = false; - private boolean isJPressDb = false; - private boolean isNeedUpgrade = false; - private String upgradeSqlFileName; - - - private static final InstallManager me = new InstallManager(); - - public static final InstallManager me() { - return me; - } - - - public void init( - String dbName, - String dbUser, - String dbPassword, - String dbHost, - int dbHostPort) { - - dbExecuter = new DbExecuter(dbName, dbUser, dbPassword, dbHost, dbHostPort); - - List tables = dbExecuter.queryTables(); - - //空数据库 - if (ArrayUtil.isNullOrEmpty(tables)) { - - dbExist = false; - isJPressDb = false; - isNeedUpgrade = false; - } - - //已经是 v3 版本 - else if (tables.containsAll(Consts.V3_TABLES)) { - dbExist = true; - isJPressDb = true; - isNeedUpgrade = false; - } - - //2.x 版本 - else if (tables.containsAll(Consts.V2_TABLES)) { - dbExist = true; - isJPressDb = true; - isNeedUpgrade = true; - upgradeSqlFileName = "v2_upgrade.sql"; - } - - //其他数据库 - else { - dbExist = true; - isJPressDb = false; - } - } - - public boolean isInited(){ - return dbExecuter != null; - } - - - public void doInitDatabase() throws SQLException { - String sqlFilePath = PathKit.getWebRootPath() + "/WEB-INF/install/sqls/install.sql"; - String installSql = FileUtil.readString(new File(sqlFilePath)); - dbExecuter.executeSql(installSql); - } - - - public void doUpgradeDatabase() throws SQLException { - String sqlFilePath = PathKit.getWebRootPath() + "/WEB-INF/install/sqls/"; - String upgradeSql = FileUtil.readString(new File(sqlFilePath, upgradeSqlFileName)); - dbExecuter.executeSql(upgradeSql); - } - - public DataSourceConfig getDataSourceConfig() { - return dbExecuter.getDataSourceConfig(); - } - - - public boolean isDbExist() { - return dbExist; - } - - public boolean isJPressDb() { - return isJPressDb; - } - - public boolean isNeedUpgrade() { - return isNeedUpgrade; - } - - public DbExecuter getDbExecuter() { - return dbExecuter; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.install; + +import com.jfinal.kit.PathKit; +import io.jboot.db.datasource.DataSourceConfig; +import io.jboot.utils.ArrayUtil; +import io.jboot.utils.FileUtil; + +import java.io.File; +import java.sql.SQLException; +import java.util.List; + +/** + * @author yang fuhai + */ +public class InstallManager { + + + private DbExecuter dbExecuter; + + private boolean dbExist = false; + private boolean isJPressDb = false; + private boolean isNeedUpgrade = false; + private String upgradeSqlFileName; + + + private static final InstallManager me = new InstallManager(); + + public static final InstallManager me() { + return me; + } + + + public void init( + String dbName, + String dbUser, + String dbPassword, + String dbHost, + int dbHostPort) { + + dbExecuter = new DbExecuter(dbName, dbUser, dbPassword, dbHost, dbHostPort); + + List tables = dbExecuter.queryTables(); + + //空数据库 + if (ArrayUtil.isNullOrEmpty(tables)) { + + dbExist = false; + isJPressDb = false; + isNeedUpgrade = false; + } + + //已经是 v3 版本 + else if (tables.containsAll(Consts.V3_TABLES)) { + dbExist = true; + isJPressDb = true; + isNeedUpgrade = false; + } + + //2.x 版本 + else if (tables.containsAll(Consts.V2_TABLES)) { + dbExist = true; + isJPressDb = true; + isNeedUpgrade = true; + upgradeSqlFileName = "v2_upgrade.sql"; + } + + //其他数据库 + else { + dbExist = true; + isJPressDb = false; + } + } + + public boolean isInited(){ + return dbExecuter != null; + } + + + public void doInitDatabase() throws SQLException { + String sqlFilePath = PathKit.getWebRootPath() + "/WEB-INF/install/sqls/install.sql"; + String installSql = FileUtil.readString(new File(sqlFilePath)); + dbExecuter.executeSql(installSql); + } + + + public void doUpgradeDatabase() throws SQLException { + String sqlFilePath = PathKit.getWebRootPath() + "/WEB-INF/install/sqls/"; + String upgradeSql = FileUtil.readString(new File(sqlFilePath, upgradeSqlFileName)); + dbExecuter.executeSql(upgradeSql); + } + + public DataSourceConfig getDataSourceConfig() { + return dbExecuter.getDataSourceConfig(); + } + + + public boolean isDbExist() { + return dbExist; + } + + public boolean isJPressDb() { + return isJPressDb; + } + + public boolean isNeedUpgrade() { + return isNeedUpgrade; + } + + public DbExecuter getDbExecuter() { + return dbExecuter; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/install/Installer.java b/jpress-core/src/main/java/io/jpress/core/install/Installer.java index e75d1efdc5f5a34e009b85951bcfb413b4146d08..7bb18b64f332faf411b6521cae9a6231d7c6c5a5 100644 --- a/jpress-core/src/main/java/io/jpress/core/install/Installer.java +++ b/jpress-core/src/main/java/io/jpress/core/install/Installer.java @@ -1,64 +1,64 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.install; - -import com.jfinal.kit.PathKit; -import io.jboot.components.event.JbootEvent; -import io.jboot.components.event.JbootEventListener; -import io.jboot.components.event.JbootEventManager; - -import java.io.File; - -public class Installer { - - public static final String INSTALL_EVENT = "jpress_install_ok"; - - private static Boolean installed = null; - - public static boolean notInstall() { - return !isInstalled(); - } - - public static boolean isInstalled() { - if (installed == null) { - init(); - } - return installed; - } - - private static void init() { - File lockFile = new File(PathKit.getRootClassPath(), "install.lock"); - boolean lockFileOk = lockFile.exists() && lockFile.isFile(); - - File propertieFile = new File(PathKit.getRootClassPath(), "jboot.properties"); - boolean propertieFileOk = propertieFile.exists() && propertieFile.isFile(); - - installed = lockFileOk && propertieFileOk; - } - - public static void setInstalled(boolean installed) { - Installer.installed = installed; - } - - public static void addListener(JbootEventListener eventListener) { - JbootEventManager.me().registerListener(eventListener, false, INSTALL_EVENT); - } - - public static void notifyAllListeners() { - JbootEventManager.me().pulish(new JbootEvent(INSTALL_EVENT, null)); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.install; + +import com.jfinal.kit.PathKit; +import io.jboot.components.event.JbootEvent; +import io.jboot.components.event.JbootEventListener; +import io.jboot.components.event.JbootEventManager; + +import java.io.File; + +public class Installer { + + public static final String INSTALL_EVENT = "jpress_install_ok"; + + private static Boolean installed = null; + + public static boolean notInstall() { + return !isInstalled(); + } + + public static boolean isInstalled() { + if (installed == null) { + init(); + } + return installed; + } + + private static void init() { + File lockFile = new File(PathKit.getRootClassPath(), "install.lock"); + boolean lockFileOk = lockFile.exists() && lockFile.isFile(); + + File propertieFile = new File(PathKit.getRootClassPath(), "jboot.properties"); + boolean propertieFileOk = propertieFile.exists() && propertieFile.isFile(); + + installed = lockFileOk && propertieFileOk; + } + + public static void setInstalled(boolean installed) { + Installer.installed = installed; + } + + public static void addListener(JbootEventListener eventListener) { + JbootEventManager.me().registerListener(eventListener, false, INSTALL_EVENT); + } + + public static void notifyAllListeners() { + JbootEventManager.me().pulish(new JbootEvent(INSTALL_EVENT, null)); + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/menu/MenuArrayList.java b/jpress-core/src/main/java/io/jpress/core/menu/MenuArrayList.java index 6d9a3b619455e55ef99abe7327884dff800285a9..b6d8e4a11a533c34e451d0e28738b22fceece5a4 100644 --- a/jpress-core/src/main/java/io/jpress/core/menu/MenuArrayList.java +++ b/jpress-core/src/main/java/io/jpress/core/menu/MenuArrayList.java @@ -1,26 +1,26 @@ -package io.jpress.core.menu; - -import java.util.ArrayList; -import java.util.Comparator; - - -public class MenuArrayList extends ArrayList { - - @Override - public boolean add(MenuGroup menuGroup) { - if (contains(menuGroup)) { - throw new RuntimeException("menuGroup:" + menuGroup + " has exits."); - } - return sort(super.add(menuGroup)); - } - - - - private boolean sort(boolean success){ - if (success) { - sort(Comparator.comparingInt(MenuGroup::getOrder)); - } - return success; - } - -} +package io.jpress.core.menu; + +import java.util.ArrayList; +import java.util.Comparator; + + +public class MenuArrayList extends ArrayList { + + @Override + public boolean add(MenuGroup menuGroup) { + if (contains(menuGroup)) { + throw new RuntimeException("menuGroup:" + menuGroup + " has exits."); + } + return sort(super.add(menuGroup)); + } + + + + private boolean sort(boolean success){ + if (success) { + sort(Comparator.comparingInt(MenuGroup::getOrder)); + } + return success; + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/menu/MenuGroup.java b/jpress-core/src/main/java/io/jpress/core/menu/MenuGroup.java index 40a289b464db0b0096236296c6d33a302f98000d..e1eacd803edc1cdb4e7ffa24b7941e919c596a67 100644 --- a/jpress-core/src/main/java/io/jpress/core/menu/MenuGroup.java +++ b/jpress-core/src/main/java/io/jpress/core/menu/MenuGroup.java @@ -1,139 +1,139 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.menu; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 的 module - * @Package io.jpress.module - */ -public class MenuGroup { - - private int order = 100; - private String text; - private String icon; - private String id; - - private List items; - - - public int getOrder() { - return order; - } - - public void setOrder(int order) { - this.order = order; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public String getIcon() { - return icon; - } - - public void setIcon(String icon) { - this.icon = icon; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } - - public void addItem(MenuItem item) { - if (items == null) { - items = new ArrayList<>(); - } - - if (items.contains(item)) { - return; - } - - items.add(item); - items.sort(Comparator.comparingInt(MenuItem::getOrder)); - } - - public void removeItem(MenuItem item) { - if (items == null || items.isEmpty()) { - return; - } - - items.removeIf(menuitem -> item.equals(menuitem)); - } - - public boolean contains(MenuItem item) { - if (items == null || items.isEmpty()) { - return false; - } - for (MenuItem i : items) { - if (i.equals(item)) { - return true; - } - } - return false; - } - - public boolean isEmpty() { - return items == null || items.isEmpty(); - } - - public String getPermission() { - return id; - } - - - @Override - public boolean equals(Object obj) { - if (obj == null || obj instanceof MenuItem == false) { - return false; - } - return ((MenuItem) obj).getId().equals(id); - } - - - @Override - public String toString() { - return "MenuGroup{" + - "order=" + order + - ", text='" + text + '\'' + - ", icon='" + icon + '\'' + - ", id='" + id + '\'' + - ", items=" + items + - '}'; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.menu; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 的 module + * @Package io.jpress.module + */ +public class MenuGroup { + + private int order = 100; + private String text; + private String icon; + private String id; + + private List items; + + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public void addItem(MenuItem item) { + if (items == null) { + items = new ArrayList<>(); + } + + if (items.contains(item)) { + return; + } + + items.add(item); + items.sort(Comparator.comparingInt(MenuItem::getOrder)); + } + + public void removeItem(MenuItem item) { + if (items == null || items.isEmpty()) { + return; + } + + items.removeIf(menuitem -> item.equals(menuitem)); + } + + public boolean contains(MenuItem item) { + if (items == null || items.isEmpty()) { + return false; + } + for (MenuItem i : items) { + if (i.equals(item)) { + return true; + } + } + return false; + } + + public boolean isEmpty() { + return items == null || items.isEmpty(); + } + + public String getPermission() { + return id; + } + + + @Override + public boolean equals(Object obj) { + if (obj == null || obj instanceof MenuItem == false) { + return false; + } + return ((MenuItem) obj).getId().equals(id); + } + + + @Override + public String toString() { + return "MenuGroup{" + + "order=" + order + + ", text='" + text + '\'' + + ", icon='" + icon + '\'' + + ", id='" + id + '\'' + + ", items=" + items + + '}'; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/menu/MenuItem.java b/jpress-core/src/main/java/io/jpress/core/menu/MenuItem.java index 1f022be9f64e9fe8cadc5a0840f4489f8723e473..ad9e844c4ae63c01643ead9d77adcf73b6f01210 100644 --- a/jpress-core/src/main/java/io/jpress/core/menu/MenuItem.java +++ b/jpress-core/src/main/java/io/jpress/core/menu/MenuItem.java @@ -1,139 +1,139 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.menu; - -import com.jfinal.core.JFinal; -import io.jpress.core.menu.annotation.AdminMenu; -import io.jpress.core.menu.annotation.UCenterMenu; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 的 module - * @Package io.jpress.module - */ -public class MenuItem { - - private String id; - private String text; - private String icon; - private String groupId; - private String url; - private int order = 100; - private String target; - - public MenuItem() { - } - - public MenuItem(UCenterMenu uCenterMenu,String actionKey) { - this.setText(uCenterMenu.text()); - this.setIcon(uCenterMenu.icon()); - this.setGroupId(uCenterMenu.groupId()); - this.setUrl(actionKey); - this.setOrder(uCenterMenu.order()); - this.setTarget(uCenterMenu.target()); - } - - public MenuItem(AdminMenu adminMenu, String actionKey) { - this.setText(adminMenu.text()); - this.setIcon(adminMenu.icon()); - this.setGroupId(adminMenu.groupId()); - this.setUrl(actionKey); - this.setOrder(adminMenu.order()); - this.setTarget(adminMenu.target()); - } - - public String getId() { - return id != null ? id : text + "--" + url; - } - - public void setId(String id) { - this.id = id; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public String getIcon() { - return icon; - } - - public void setIcon(String icon) { - this.icon = icon; - } - - public String getGroupId() { - return groupId; - } - - public void setGroupId(String groupId) { - this.groupId = groupId; - } - - public String getUrl() { - return JFinal.me().getContextPath() + url; - } - - public void setUrl(String url) { - this.url = url; - } - - public int getOrder() { - return order; - } - - public void setOrder(int order) { - this.order = order; - } - - public String getPermission() { - return groupId + ":" + url; - } - - public String getTarget() { - return target; - } - - public void setTarget(String target) { - this.target = target; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || obj instanceof MenuItem == false) { - return false; - } - return ((MenuItem) obj).getId().equals(id); - } - - - - @Override - public String toString() { - return "MenuItem{" + - "text='" + text + '\'' + - ", icon='" + icon + '\'' + - ", groupId='" + groupId + '\'' + - ", url='" + url + '\'' + - ", order=" + order + - '}'; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.menu; + +import com.jfinal.core.JFinal; +import io.jpress.core.menu.annotation.AdminMenu; +import io.jpress.core.menu.annotation.UCenterMenu; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 的 module + * @Package io.jpress.module + */ +public class MenuItem { + + private String id; + private String text; + private String icon; + private String groupId; + private String url; + private int order = 100; + private String target; + + public MenuItem() { + } + + public MenuItem(UCenterMenu uCenterMenu,String actionKey) { + this.setText(uCenterMenu.text()); + this.setIcon(uCenterMenu.icon()); + this.setGroupId(uCenterMenu.groupId()); + this.setUrl(actionKey); + this.setOrder(uCenterMenu.order()); + this.setTarget(uCenterMenu.target()); + } + + public MenuItem(AdminMenu adminMenu, String actionKey) { + this.setText(adminMenu.text()); + this.setIcon(adminMenu.icon()); + this.setGroupId(adminMenu.groupId()); + this.setUrl(actionKey); + this.setOrder(adminMenu.order()); + this.setTarget(adminMenu.target()); + } + + public String getId() { + return id != null ? id : text + "--" + url; + } + + public void setId(String id) { + this.id = id; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getUrl() { + return JFinal.me().getContextPath() + url; + } + + public void setUrl(String url) { + this.url = url; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public String getPermission() { + return groupId + ":" + url; + } + + public String getTarget() { + return target; + } + + public void setTarget(String target) { + this.target = target; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj instanceof MenuItem == false) { + return false; + } + return ((MenuItem) obj).getId().equals(id); + } + + + + @Override + public String toString() { + return "MenuItem{" + + "text='" + text + '\'' + + ", icon='" + icon + '\'' + + ", groupId='" + groupId + '\'' + + ", url='" + url + '\'' + + ", order=" + order + + '}'; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/menu/MenuManager.java b/jpress-core/src/main/java/io/jpress/core/menu/MenuManager.java index 66d6bd382fad46e7c7626fabcf1a1dd996861dbc..eceb073c2fea5d5fb8be53aed9e808fe753cf10f 100644 --- a/jpress-core/src/main/java/io/jpress/core/menu/MenuManager.java +++ b/jpress-core/src/main/java/io/jpress/core/menu/MenuManager.java @@ -1,305 +1,305 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.menu; - -import com.jfinal.core.Action; -import com.jfinal.core.JFinal; -import io.jboot.components.event.JbootEvent; -import io.jboot.components.event.JbootEventListener; -import io.jpress.JPressConsts; -import io.jpress.core.install.Installer; -import io.jpress.core.menu.annotation.AdminMenu; -import io.jpress.core.menu.annotation.UCenterMenu; -import io.jpress.core.module.ModuleListener; -import io.jpress.core.module.ModuleManager; -import io.jpress.web.base.AdminControllerBase; - -import java.lang.reflect.Method; -import java.util.*; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 的 module - * @Package io.jpress.module - */ -public class MenuManager implements JbootEventListener { - - private static final MenuManager me = new MenuManager(); - - private MenuArrayList systemMenus = new MenuArrayList(); - private MenuArrayList moduleMenus = new MenuArrayList(); - private MenuArrayList ucenterMenus = new MenuArrayList(); - - private MenuManager() { - - } - - public static MenuManager me() { - return me; - } - - public void init() { - - - if (Installer.notInstall()) { - Installer.addListener(this); - return; - } - - //初始化后台的固定菜单 - initAdminSystemMenuGroup(); - - //初始化后台的 module 菜单 - initAdminMenuItems(); - - //初始化 用户中心菜单 - initUCenterMenuItems(); - } - - - /** - * 初始化 后台的固定菜单 - * 备注:子初始化菜单组,不初始化子菜单,子菜单由注解完成 - */ - private void initAdminSystemMenuGroup() { - - MenuGroup orderMenuGroup = new MenuGroup(); - orderMenuGroup.setId(JPressConsts.SYSTEM_MENU_ORDER); - orderMenuGroup.setText("财务"); - orderMenuGroup.setIcon(""); - systemMenus.add(orderMenuGroup); - - - MenuGroup userMenuGroup = new MenuGroup(); - userMenuGroup.setId(JPressConsts.SYSTEM_MENU_USER); - userMenuGroup.setText("用户"); - userMenuGroup.setIcon(""); - systemMenus.add(userMenuGroup); - - - MenuGroup wechatMenuGroup = new MenuGroup(); - wechatMenuGroup.setId(JPressConsts.SYSTEM_MENU_WECHAT_PUBULIC_ACCOUNT); - wechatMenuGroup.setText("微信"); - wechatMenuGroup.setIcon(""); - systemMenus.add(wechatMenuGroup); - - - MenuGroup templateMenuGroup = new MenuGroup(); - templateMenuGroup.setId(JPressConsts.SYSTEM_MENU_TEMPLATE); - templateMenuGroup.setText("模板"); - templateMenuGroup.setIcon(""); - systemMenus.add(templateMenuGroup); - - - MenuGroup addonMenuGroup = new MenuGroup(); - addonMenuGroup.setId(JPressConsts.SYSTEM_MENU_ADDON); - addonMenuGroup.setText("插件"); - addonMenuGroup.setIcon(""); - systemMenus.add(addonMenuGroup); - - - MenuGroup settingMenuGroup = new MenuGroup(); - settingMenuGroup.setId(JPressConsts.SYSTEM_MENU_SYSTEM); - settingMenuGroup.setText("系统"); - settingMenuGroup.setIcon(""); - systemMenus.add(settingMenuGroup); - - } - - - /** - * 初始化 子菜单 - */ - private void initAdminMenuItems() { - - for (ModuleListener listener : ModuleManager.me().getListeners()) { - listener.onConfigAdminMenu(moduleMenus); - } - - MenuGroup attachmentMenuGroup = new MenuGroup(); - attachmentMenuGroup.setId(JPressConsts.SYSTEM_MENU_ATTACHMENT); - attachmentMenuGroup.setText("附件"); - attachmentMenuGroup.setIcon(""); - moduleMenus.add(attachmentMenuGroup); - - - addMenuItems(buildAdminMenuItems()); - } - - public void deleteMenuItem(String id) { - for (MenuGroup group : systemMenus) { - if (group.getItems() != null) { - group.getItems().removeIf(item -> item.getId().equals(id)); - } - } - for (MenuGroup group : moduleMenus) { - if (group.getItems() != null) { - group.getItems().removeIf(item -> item.getId().equals(id)); - } - } - for (MenuGroup group : ucenterMenus) { - if (group.getItems() != null) { - group.getItems().removeIf(item -> item.getId().equals(id)); - } - } - } - - public void deleteMenuGroup(String id) { - systemMenus.removeIf(group -> id.equals(group.getId())); - moduleMenus.removeIf(group -> id.equals(group.getId())); - ucenterMenus.removeIf(group -> id.equals(group.getId())); - } - - public void addMenuItems(List items) { - if (items == null) { - return; - } - for (MenuItem item : items) { - addMenuItem(item); - } - } - - public void addMenuItem(MenuItem item) { - String ctxPath = JFinal.me().getContextPath(); - for (MenuGroup group : systemMenus) { - if (group.getId().equals(item.getGroupId()) && item.getUrl().startsWith(ctxPath + "/admin")) { - group.addItem(item); - } - } - for (MenuGroup group : moduleMenus) { - if (group.getId().equals(item.getGroupId()) && item.getUrl().startsWith(ctxPath + "/admin")) { - group.addItem(item); - } - } - for (MenuGroup group : ucenterMenus) { - if (group.getId().equals(item.getGroupId()) && item.getUrl().startsWith(ctxPath + "/ucenter")) { - group.addItem(item); - } - } - } - - private void initUCenterMenuItems() { - - for (ModuleListener listener : ModuleManager.me().getListeners()) { - listener.onConfigUcenterMenu(ucenterMenus); - } - - - MenuGroup commentMenuGroup = new MenuGroup(); - commentMenuGroup.setId("comment"); - commentMenuGroup.setText("我的评论"); - commentMenuGroup.setIcon(""); - commentMenuGroup.setOrder(88); - ucenterMenus.add(commentMenuGroup); - - - MenuGroup favoriteMenuGroup = new MenuGroup(); - favoriteMenuGroup.setId("favorite"); - favoriteMenuGroup.setText("我的收藏"); - favoriteMenuGroup.setIcon(""); - favoriteMenuGroup.setOrder(99); - ucenterMenus.add(favoriteMenuGroup); - - addMenuItems(buildUCenterMenuItems()); - } - - - // 用于排除掉 BaseController 中的几个成为了 action 的方法 - private static Set excludedMethodName = buildExcludedMethodName(); - - private static Set buildExcludedMethodName() { - Set excludedMethodName = new HashSet(); - Method[] methods = AdminControllerBase.class.getMethods(); - for (Method m : methods) { - excludedMethodName.add(m.getName()); - } - return excludedMethodName; - } - - private static List buildAdminMenuItems() { - - List adminMenuItems = new ArrayList<>(); - List allActionKeys = JFinal.me().getAllActionKeys(); - - String[] urlPara = new String[1]; - for (String actionKey : allActionKeys) { - - if (actionKey.startsWith("/admin")) { - Action action = JFinal.me().getAction(actionKey, urlPara); - if (action == null || excludedMethodName.contains(action.getMethodName())) { - continue; - } - - AdminMenu adminMenu = action.getMethod().getAnnotation(AdminMenu.class); - if (adminMenu == null) { - continue; - } - - adminMenuItems.add(new MenuItem(adminMenu, actionKey)); - } - } - - return adminMenuItems; - } - - private static List buildUCenterMenuItems() { - - List adminMenuItems = new ArrayList<>(); - List allActionKeys = JFinal.me().getAllActionKeys(); - - String[] urlPara = new String[1]; - for (String actionKey : allActionKeys) { - // 只处理后台的权限 和 API的权限 - if (actionKey.startsWith("/ucenter")) { - - Action action = JFinal.me().getAction(actionKey, urlPara); - if (action == null || excludedMethodName.contains(action.getMethodName())) { - continue; - } - - UCenterMenu uCenterMenu = action.getMethod().getAnnotation(UCenterMenu.class); - if (uCenterMenu == null) { - continue; - } - - adminMenuItems.add(new MenuItem(uCenterMenu, actionKey)); - } - } - - return adminMenuItems; - } - - - public List getSystemMenus() { - return systemMenus; - } - - public List getModuleMenus() { - return moduleMenus; - } - - public List getUcenterMenus() { - return ucenterMenus; - } - - @Override - public void onEvent(JbootEvent jbootEvent) { - init(); - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.menu; + +import com.jfinal.core.Action; +import com.jfinal.core.JFinal; +import io.jboot.components.event.JbootEvent; +import io.jboot.components.event.JbootEventListener; +import io.jpress.JPressConsts; +import io.jpress.core.install.Installer; +import io.jpress.core.menu.annotation.AdminMenu; +import io.jpress.core.menu.annotation.UCenterMenu; +import io.jpress.core.module.ModuleListener; +import io.jpress.core.module.ModuleManager; +import io.jpress.web.base.AdminControllerBase; + +import java.lang.reflect.Method; +import java.util.*; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 的 module + * @Package io.jpress.module + */ +public class MenuManager implements JbootEventListener { + + private static final MenuManager me = new MenuManager(); + + private MenuArrayList systemMenus = new MenuArrayList(); + private MenuArrayList moduleMenus = new MenuArrayList(); + private MenuArrayList ucenterMenus = new MenuArrayList(); + + private MenuManager() { + + } + + public static MenuManager me() { + return me; + } + + public void init() { + + + if (Installer.notInstall()) { + Installer.addListener(this); + return; + } + + //初始化后台的固定菜单 + initAdminSystemMenuGroup(); + + //初始化后台的 module 菜单 + initAdminMenuItems(); + + //初始化 用户中心菜单 + initUCenterMenuItems(); + } + + + /** + * 初始化 后台的固定菜单 + * 备注:子初始化菜单组,不初始化子菜单,子菜单由注解完成 + */ + private void initAdminSystemMenuGroup() { + + MenuGroup orderMenuGroup = new MenuGroup(); + orderMenuGroup.setId(JPressConsts.SYSTEM_MENU_ORDER); + orderMenuGroup.setText("财务"); + orderMenuGroup.setIcon(""); + systemMenus.add(orderMenuGroup); + + + MenuGroup userMenuGroup = new MenuGroup(); + userMenuGroup.setId(JPressConsts.SYSTEM_MENU_USER); + userMenuGroup.setText("用户"); + userMenuGroup.setIcon(""); + systemMenus.add(userMenuGroup); + + + MenuGroup wechatMenuGroup = new MenuGroup(); + wechatMenuGroup.setId(JPressConsts.SYSTEM_MENU_WECHAT_PUBULIC_ACCOUNT); + wechatMenuGroup.setText("微信"); + wechatMenuGroup.setIcon(""); + systemMenus.add(wechatMenuGroup); + + + MenuGroup templateMenuGroup = new MenuGroup(); + templateMenuGroup.setId(JPressConsts.SYSTEM_MENU_TEMPLATE); + templateMenuGroup.setText("模板"); + templateMenuGroup.setIcon(""); + systemMenus.add(templateMenuGroup); + + + MenuGroup addonMenuGroup = new MenuGroup(); + addonMenuGroup.setId(JPressConsts.SYSTEM_MENU_ADDON); + addonMenuGroup.setText("插件"); + addonMenuGroup.setIcon(""); + systemMenus.add(addonMenuGroup); + + + MenuGroup settingMenuGroup = new MenuGroup(); + settingMenuGroup.setId(JPressConsts.SYSTEM_MENU_SYSTEM); + settingMenuGroup.setText("系统"); + settingMenuGroup.setIcon(""); + systemMenus.add(settingMenuGroup); + + } + + + /** + * 初始化 子菜单 + */ + private void initAdminMenuItems() { + + for (ModuleListener listener : ModuleManager.me().getListeners()) { + listener.onConfigAdminMenu(moduleMenus); + } + + MenuGroup attachmentMenuGroup = new MenuGroup(); + attachmentMenuGroup.setId(JPressConsts.SYSTEM_MENU_ATTACHMENT); + attachmentMenuGroup.setText("附件"); + attachmentMenuGroup.setIcon(""); + moduleMenus.add(attachmentMenuGroup); + + + addMenuItems(buildAdminMenuItems()); + } + + public void deleteMenuItem(String id) { + for (MenuGroup group : systemMenus) { + if (group.getItems() != null) { + group.getItems().removeIf(item -> item.getId().equals(id)); + } + } + for (MenuGroup group : moduleMenus) { + if (group.getItems() != null) { + group.getItems().removeIf(item -> item.getId().equals(id)); + } + } + for (MenuGroup group : ucenterMenus) { + if (group.getItems() != null) { + group.getItems().removeIf(item -> item.getId().equals(id)); + } + } + } + + public void deleteMenuGroup(String id) { + systemMenus.removeIf(group -> id.equals(group.getId())); + moduleMenus.removeIf(group -> id.equals(group.getId())); + ucenterMenus.removeIf(group -> id.equals(group.getId())); + } + + public void addMenuItems(List items) { + if (items == null) { + return; + } + for (MenuItem item : items) { + addMenuItem(item); + } + } + + public void addMenuItem(MenuItem item) { + String ctxPath = JFinal.me().getContextPath(); + for (MenuGroup group : systemMenus) { + if (group.getId().equals(item.getGroupId()) && item.getUrl().startsWith(ctxPath + "/admin")) { + group.addItem(item); + } + } + for (MenuGroup group : moduleMenus) { + if (group.getId().equals(item.getGroupId()) && item.getUrl().startsWith(ctxPath + "/admin")) { + group.addItem(item); + } + } + for (MenuGroup group : ucenterMenus) { + if (group.getId().equals(item.getGroupId()) && item.getUrl().startsWith(ctxPath + "/ucenter")) { + group.addItem(item); + } + } + } + + private void initUCenterMenuItems() { + + for (ModuleListener listener : ModuleManager.me().getListeners()) { + listener.onConfigUcenterMenu(ucenterMenus); + } + + + MenuGroup commentMenuGroup = new MenuGroup(); + commentMenuGroup.setId("comment"); + commentMenuGroup.setText("我的评论"); + commentMenuGroup.setIcon(""); + commentMenuGroup.setOrder(88); + ucenterMenus.add(commentMenuGroup); + + + MenuGroup favoriteMenuGroup = new MenuGroup(); + favoriteMenuGroup.setId("favorite"); + favoriteMenuGroup.setText("我的收藏"); + favoriteMenuGroup.setIcon(""); + favoriteMenuGroup.setOrder(99); + ucenterMenus.add(favoriteMenuGroup); + + addMenuItems(buildUCenterMenuItems()); + } + + + // 用于排除掉 BaseController 中的几个成为了 action 的方法 + private static Set excludedMethodName = buildExcludedMethodName(); + + private static Set buildExcludedMethodName() { + Set excludedMethodName = new HashSet(); + Method[] methods = AdminControllerBase.class.getMethods(); + for (Method m : methods) { + excludedMethodName.add(m.getName()); + } + return excludedMethodName; + } + + private static List buildAdminMenuItems() { + + List adminMenuItems = new ArrayList<>(); + List allActionKeys = JFinal.me().getAllActionKeys(); + + String[] urlPara = new String[1]; + for (String actionKey : allActionKeys) { + + if (actionKey.startsWith("/admin")) { + Action action = JFinal.me().getAction(actionKey, urlPara); + if (action == null || excludedMethodName.contains(action.getMethodName())) { + continue; + } + + AdminMenu adminMenu = action.getMethod().getAnnotation(AdminMenu.class); + if (adminMenu == null) { + continue; + } + + adminMenuItems.add(new MenuItem(adminMenu, actionKey)); + } + } + + return adminMenuItems; + } + + private static List buildUCenterMenuItems() { + + List adminMenuItems = new ArrayList<>(); + List allActionKeys = JFinal.me().getAllActionKeys(); + + String[] urlPara = new String[1]; + for (String actionKey : allActionKeys) { + // 只处理后台的权限 和 API的权限 + if (actionKey.startsWith("/ucenter")) { + + Action action = JFinal.me().getAction(actionKey, urlPara); + if (action == null || excludedMethodName.contains(action.getMethodName())) { + continue; + } + + UCenterMenu uCenterMenu = action.getMethod().getAnnotation(UCenterMenu.class); + if (uCenterMenu == null) { + continue; + } + + adminMenuItems.add(new MenuItem(uCenterMenu, actionKey)); + } + } + + return adminMenuItems; + } + + + public List getSystemMenus() { + return systemMenus; + } + + public List getModuleMenus() { + return moduleMenus; + } + + public List getUcenterMenus() { + return ucenterMenus; + } + + @Override + public void onEvent(JbootEvent jbootEvent) { + init(); + } + + +} diff --git a/jpress-core/src/main/java/io/jpress/core/menu/annotation/AdminMenu.java b/jpress-core/src/main/java/io/jpress/core/menu/annotation/AdminMenu.java index 738d5c70298ebe547425d94d046fbe7c5be62448..85dee6545ceb8a502d389a284f0d18102f15546c 100644 --- a/jpress-core/src/main/java/io/jpress/core/menu/annotation/AdminMenu.java +++ b/jpress-core/src/main/java/io/jpress/core/menu/annotation/AdminMenu.java @@ -1,40 +1,40 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.menu.annotation; - -import java.lang.annotation.*; - -/** - * 用来给给Controller的方法进行标注,申明此方法为一个后台菜单 - * 后台菜单被包含在 group里,而 group 是由module来定义的,jpress系统也内置了几个group - *

    - * groupId 用来标识 这个方法被放在哪个group里 - */ -@Inherited -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD}) -public @interface AdminMenu { - - String groupId(); - - String text(); - - String icon() default ""; - - String target() default ""; - - int order() default 100; //越小在越前面 +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.menu.annotation; + +import java.lang.annotation.*; + +/** + * 用来给给Controller的方法进行标注,申明此方法为一个后台菜单 + * 后台菜单被包含在 group里,而 group 是由module来定义的,jpress系统也内置了几个group + *

    + * groupId 用来标识 这个方法被放在哪个group里 + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface AdminMenu { + + String groupId(); + + String text(); + + String icon() default ""; + + String target() default ""; + + int order() default 100; //越小在越前面 } \ No newline at end of file diff --git a/jpress-core/src/main/java/io/jpress/core/menu/annotation/UCenterMenu.java b/jpress-core/src/main/java/io/jpress/core/menu/annotation/UCenterMenu.java index afefe8d4d56cd222caedfff5cfa4f6f00be93261..d33b79ff563ab84bfa3f9011d78821cf0eb46254 100644 --- a/jpress-core/src/main/java/io/jpress/core/menu/annotation/UCenterMenu.java +++ b/jpress-core/src/main/java/io/jpress/core/menu/annotation/UCenterMenu.java @@ -1,40 +1,40 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.menu.annotation; - -import java.lang.annotation.*; - -/** - * 用来给给Controller的方法进行标注,申明此方法为一个用户中心的菜单 - *

    - * groupId 用来标识 这个方法被放在哪个group里 - */ -@Inherited -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD}) -public @interface UCenterMenu { - - String groupId(); - - String text(); - - String icon() default ""; - - String target() default ""; - - - int order() default 100; //越小在越前面 +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.menu.annotation; + +import java.lang.annotation.*; + +/** + * 用来给给Controller的方法进行标注,申明此方法为一个用户中心的菜单 + *

    + * groupId 用来标识 这个方法被放在哪个group里 + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface UCenterMenu { + + String groupId(); + + String text(); + + String icon() default ""; + + String target() default ""; + + + int order() default 100; //越小在越前面 } \ No newline at end of file diff --git a/jpress-core/src/main/java/io/jpress/core/module/ModuleBase.java b/jpress-core/src/main/java/io/jpress/core/module/ModuleBase.java index 599ba7c85a37ba545c608f7e84cec70f80c9874a..e28e01f55438e29da8960e7682149dda84cc560d 100644 --- a/jpress-core/src/main/java/io/jpress/core/module/ModuleBase.java +++ b/jpress-core/src/main/java/io/jpress/core/module/ModuleBase.java @@ -1,53 +1,53 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.module; - -import com.jfinal.core.Controller; -import io.jboot.core.listener.JbootAppListener; -import io.jboot.core.listener.JbootAppListenerBase; -import io.jpress.core.menu.MenuGroup; - -import java.util.List; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 监听器 - * @Package io.jpress - */ -public class ModuleBase extends JbootAppListenerBase implements ModuleListener, JbootAppListener { - - - @Override - public String onRenderDashboardBox(Controller controller) { - return null; - } - - @Override - public String onRenderToolsBox(Controller controller) { - return null; - } - - @Override - public void onConfigAdminMenu(List adminMenus) { - - } - - @Override - public void onConfigUcenterMenu(List ucenterMenus) { - - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.module; + +import com.jfinal.core.Controller; +import io.jboot.core.listener.JbootAppListener; +import io.jboot.core.listener.JbootAppListenerBase; +import io.jpress.core.menu.MenuGroup; + +import java.util.List; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 监听器 + * @Package io.jpress + */ +public class ModuleBase extends JbootAppListenerBase implements ModuleListener, JbootAppListener { + + + @Override + public String onRenderDashboardBox(Controller controller) { + return null; + } + + @Override + public String onRenderToolsBox(Controller controller) { + return null; + } + + @Override + public void onConfigAdminMenu(List adminMenus) { + + } + + @Override + public void onConfigUcenterMenu(List ucenterMenus) { + + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/module/ModuleListener.java b/jpress-core/src/main/java/io/jpress/core/module/ModuleListener.java index 771a83f9fab3e60ec8fe9c05d476c5286d27460a..93902695934b04b4637a3888a6119ab536be9ad5 100644 --- a/jpress-core/src/main/java/io/jpress/core/module/ModuleListener.java +++ b/jpress-core/src/main/java/io/jpress/core/module/ModuleListener.java @@ -1,68 +1,68 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.module; - -import com.jfinal.core.Controller; -import io.jpress.core.menu.MenuGroup; - -import java.util.List; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 监听器 - * @Package io.jpress - */ -public interface ModuleListener { - - /** - * 对后台的面板进行渲染 - *

    - * 返回的内容是html 文件地址,html 文件应该只包含 单个div ,这个 div 会被嵌套在 面板里 - *

    - * 暂时不支持顺序 - * - * @param controller - * @return 返回要 html 文件地址 - */ - public String onRenderDashboardBox(Controller controller); - - - /** - * 对后台的 "工具箱" 进行进行渲染 - * - * @param controller - * @return - */ - public String onRenderToolsBox(Controller controller); - - - /** - * 配置后台的菜单 - * - * @param adminMenus - */ - public void onConfigAdminMenu(List adminMenus); - - - /** - * 配置用户中心的菜单 - * - * @param ucenterMenus - */ - public void onConfigUcenterMenu(List ucenterMenus); - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.module; + +import com.jfinal.core.Controller; +import io.jpress.core.menu.MenuGroup; + +import java.util.List; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 监听器 + * @Package io.jpress + */ +public interface ModuleListener { + + /** + * 对后台的面板进行渲染 + *

    + * 返回的内容是html 文件地址,html 文件应该只包含 单个div ,这个 div 会被嵌套在 面板里 + *

    + * 暂时不支持顺序 + * + * @param controller + * @return 返回要 html 文件地址 + */ + public String onRenderDashboardBox(Controller controller); + + + /** + * 对后台的 "工具箱" 进行进行渲染 + * + * @param controller + * @return + */ + public String onRenderToolsBox(Controller controller); + + + /** + * 配置后台的菜单 + * + * @param adminMenus + */ + public void onConfigAdminMenu(List adminMenus); + + + /** + * 配置用户中心的菜单 + * + * @param ucenterMenus + */ + public void onConfigUcenterMenu(List ucenterMenus); + +} diff --git a/jpress-core/src/main/java/io/jpress/core/module/ModuleListenerBase.java b/jpress-core/src/main/java/io/jpress/core/module/ModuleListenerBase.java index a5a8087b65b8d664cda208969c3ffef228630757..41b589bd488a3e56aa81cbd0ac06633157ef2116 100644 --- a/jpress-core/src/main/java/io/jpress/core/module/ModuleListenerBase.java +++ b/jpress-core/src/main/java/io/jpress/core/module/ModuleListenerBase.java @@ -1,52 +1,52 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.module; - -import com.jfinal.core.Controller; -import io.jpress.core.menu.MenuGroup; - -import java.util.List; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: JPress 监听器 - * @Package io.jpress - */ -@Deprecated -public class ModuleListenerBase implements ModuleListener { - - - @Override - public String onRenderDashboardBox(Controller controller) { - return null; - } - - @Override - public String onRenderToolsBox(Controller controller) { - return null; - } - - @Override - public void onConfigAdminMenu(List adminMenus) { - - } - - @Override - public void onConfigUcenterMenu(List ucenterMenus) { - - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.module; + +import com.jfinal.core.Controller; +import io.jpress.core.menu.MenuGroup; + +import java.util.List; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: JPress 监听器 + * @Package io.jpress + */ +@Deprecated +public class ModuleListenerBase implements ModuleListener { + + + @Override + public String onRenderDashboardBox(Controller controller) { + return null; + } + + @Override + public String onRenderToolsBox(Controller controller) { + return null; + } + + @Override + public void onConfigAdminMenu(List adminMenus) { + + } + + @Override + public void onConfigUcenterMenu(List ucenterMenus) { + + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/module/ModuleManager.java b/jpress-core/src/main/java/io/jpress/core/module/ModuleManager.java index 3019d190a48374ea9564baba838b8d22e7fa2ec7..135a9e41ec64027dbbfc17f8c8dd30871bb01fba 100644 --- a/jpress-core/src/main/java/io/jpress/core/module/ModuleManager.java +++ b/jpress-core/src/main/java/io/jpress/core/module/ModuleManager.java @@ -1,75 +1,75 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.module; - -import io.jboot.utils.ClassScanner; -import io.jboot.utils.ClassUtil; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Package io.jpress.core.module - */ -public class ModuleManager { - private static final ModuleManager me = new ModuleManager(); - private List moduleListeners = new ArrayList<>(); - - - private ModuleManager() { - initModuleListeners(); - } - - public static ModuleManager me() { - return me; - } - - - public List getListeners() { - return moduleListeners; - } - - /** - * 初始化 监听器 - * 其他 module 会在监听器里完成所有需要的配置 - */ - private void initModuleListeners() { - - List> classes = ClassScanner.scanSubClass(ModuleListener.class, true); - if (classes == null) { - return; - } - - for (Class moduleListenerClass : classes) { - addListener(ClassUtil.newInstance(moduleListenerClass)); - } - } - - public void addListener(ModuleListener listener){ - moduleListeners.add(listener); - } - - public void removeListener(ModuleListener listener){ - moduleListeners.remove(listener); - } - - public void removeListener(Class clazz){ - moduleListeners.removeIf(listener -> listener.getClass() == clazz); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.module; + +import io.jboot.utils.ClassScanner; +import io.jboot.utils.ClassUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Package io.jpress.core.module + */ +public class ModuleManager { + private static final ModuleManager me = new ModuleManager(); + private List moduleListeners = new ArrayList<>(); + + + private ModuleManager() { + initModuleListeners(); + } + + public static ModuleManager me() { + return me; + } + + + public List getListeners() { + return moduleListeners; + } + + /** + * 初始化 监听器 + * 其他 module 会在监听器里完成所有需要的配置 + */ + private void initModuleListeners() { + + List> classes = ClassScanner.scanSubClass(ModuleListener.class, true); + if (classes == null) { + return; + } + + for (Class moduleListenerClass : classes) { + addListener(ClassUtil.newInstance(moduleListenerClass)); + } + } + + public void addListener(ModuleListener listener){ + moduleListeners.add(listener); + } + + public void removeListener(ModuleListener listener){ + moduleListeners.remove(listener); + } + + public void removeListener(Class clazz){ + moduleListeners.removeIf(listener -> listener.getClass() == clazz); + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/ehcache/EhcacheManager.java b/jpress-core/src/main/java/io/jpress/core/support/ehcache/EhcacheManager.java index c56d441500ba06c29e6d5652e677a966307024cb..a181deddb94ed8a448c2a89b4edcb8d87ad6db8e 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/ehcache/EhcacheManager.java +++ b/jpress-core/src/main/java/io/jpress/core/support/ehcache/EhcacheManager.java @@ -1,96 +1,96 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.ehcache; - - -import io.jboot.app.config.JbootConfigManager; -import io.jboot.utils.StrUtil; -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.config.CacheConfiguration; -import net.sf.ehcache.config.Configuration; -import net.sf.ehcache.config.ConfigurationFactory; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 为什么需要 EhcacheManager ? - *

    - * EhcacheManager 的主要作用是用于初始化 EhCache 的 CacheManager - * 默认情况下,Ehcache 是通过 默认的(系统的) Classloader 加载数据的 - * 但是由于 JPress 内置了插件机制,插件的所有class都是通过插件自己的 Classloader 进行加载 - * 这样就会导致 EhCache 和 插件的 Classloader 不是通过一个 Classloader,当插件使用ehcache缓存的时候, - * 就会导致 ClassNotFound 的异常出现 - *

    - * 所以,此类的主要作用,是对 EhCache Classloader 进行配置,保证能够加载到 插件自己的 Class - *

    - * 另外:对于插件来说,每个插件必须使用自己的 Classloader,才能保证 插件在后台进行 安装、卸载、停止、启用的正常工作 - * 否则当用户卸载插件后重新安装,无法加载到新的Class(之前的Class还在内存里) - */ -public class EhcacheManager { - - private static EhcacheClassloader ehcacheClassloader = new EhcacheClassloader(); - - public static void init() { - - Configuration config = ConfigurationFactory.parseConfiguration(); - config.setClassLoader(ehcacheClassloader); - - String maxBytesLocalHeap = JbootConfigManager.me().getConfigValue("jpress.ehcache.maxBytesLocalHeap"); - config.setMaxBytesLocalHeap(StrUtil.obtainDefaultIfBlank(maxBytesLocalHeap, "100M")); - - String maxBytesLocalDisk = JbootConfigManager.me().getConfigValue("jpress.ehcache.maxBytesLocalDisk"); - config.setMaxBytesLocalDisk(StrUtil.obtainDefaultIfBlank(maxBytesLocalDisk, "5G")); - - CacheConfiguration cacheConfiguration = new CacheConfiguration(); - cacheConfiguration.setClassLoader(ehcacheClassloader); - config.defaultCache(cacheConfiguration); - - CacheManager.create(config); - } - - public static void addMapping(String className, ClassLoader classLoader) { - ehcacheClassloader.addMapping(className, classLoader); - } - - - public static class EhcacheClassloader extends ClassLoader { - - private ClassLoader parent = EhcacheClassloader.class.getClassLoader(); - private Map classLoaderCache = null; - - - public synchronized void addMapping(String className, ClassLoader classLoader) { - if (classLoaderCache == null) { - classLoaderCache = new ConcurrentHashMap<>(); - } - classLoaderCache.put(className, classLoader); - } - - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - if (classLoaderCache == null || classLoaderCache.isEmpty()) { - return parent.loadClass(name); - } - ClassLoader c = classLoaderCache.get(name); - if (c == null) { - c = parent; - } - return c.loadClass(name); - } - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.ehcache; + + +import io.jboot.app.config.JbootConfigManager; +import io.jboot.utils.StrUtil; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.config.CacheConfiguration; +import net.sf.ehcache.config.Configuration; +import net.sf.ehcache.config.ConfigurationFactory; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 为什么需要 EhcacheManager ? + *

    + * EhcacheManager 的主要作用是用于初始化 EhCache 的 CacheManager + * 默认情况下,Ehcache 是通过 默认的(系统的) Classloader 加载数据的 + * 但是由于 JPress 内置了插件机制,插件的所有class都是通过插件自己的 Classloader 进行加载 + * 这样就会导致 EhCache 和 插件的 Classloader 不是通过一个 Classloader,当插件使用ehcache缓存的时候, + * 就会导致 ClassNotFound 的异常出现 + *

    + * 所以,此类的主要作用,是对 EhCache Classloader 进行配置,保证能够加载到 插件自己的 Class + *

    + * 另外:对于插件来说,每个插件必须使用自己的 Classloader,才能保证 插件在后台进行 安装、卸载、停止、启用的正常工作 + * 否则当用户卸载插件后重新安装,无法加载到新的Class(之前的Class还在内存里) + */ +public class EhcacheManager { + + private static EhcacheClassloader ehcacheClassloader = new EhcacheClassloader(); + + public static void init() { + + Configuration config = ConfigurationFactory.parseConfiguration(); + config.setClassLoader(ehcacheClassloader); + + String maxBytesLocalHeap = JbootConfigManager.me().getConfigValue("jpress.ehcache.maxBytesLocalHeap"); + config.setMaxBytesLocalHeap(StrUtil.obtainDefaultIfBlank(maxBytesLocalHeap, "100M")); + + String maxBytesLocalDisk = JbootConfigManager.me().getConfigValue("jpress.ehcache.maxBytesLocalDisk"); + config.setMaxBytesLocalDisk(StrUtil.obtainDefaultIfBlank(maxBytesLocalDisk, "5G")); + + CacheConfiguration cacheConfiguration = new CacheConfiguration(); + cacheConfiguration.setClassLoader(ehcacheClassloader); + config.defaultCache(cacheConfiguration); + + CacheManager.create(config); + } + + public static void addMapping(String className, ClassLoader classLoader) { + ehcacheClassloader.addMapping(className, classLoader); + } + + + public static class EhcacheClassloader extends ClassLoader { + + private ClassLoader parent = EhcacheClassloader.class.getClassLoader(); + private Map classLoaderCache = null; + + + public synchronized void addMapping(String className, ClassLoader classLoader) { + if (classLoaderCache == null) { + classLoaderCache = new ConcurrentHashMap<>(); + } + classLoaderCache.put(className, classLoader); + } + + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (classLoaderCache == null || classLoaderCache.isEmpty()) { + return parent.loadClass(name); + } + ClassLoader c = classLoaderCache.get(name); + if (c == null) { + c = parent; + } + return c.loadClass(name); + } + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartField.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartField.java index 05b8d8dde1c02fbc3de8b5dcda7cd19399c228bc..e764a4e6b8ff0d93fa03b0e5f270951bc0aeceb1 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartField.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartField.java @@ -1,216 +1,216 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield; - -import com.jfinal.core.Controller; -import com.jfinal.kit.StrKit; -import com.jfinal.plugin.activerecord.Model; -import io.jboot.utils.StrUtil; -import io.jboot.web.controller.JbootControllerContext; - -import java.lang.reflect.Method; -import java.util.Map; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: 文章字段 - */ -public class SmartField { - - public static final String TYPE_INPUT = "input"; - public static final String TYPE_TEXTAREA = "textarea"; - public static final String TYPE_SELECT = "select"; - public static final String TYPE_CHECKBOX = "checkbox"; - public static final String TYPE_SWITCH = "switch"; - public static final String TYPE_RADIO = "radio"; - public static final String TYPE_IMAGE = "image"; - public static final String TYPE_FILE = "file"; - public static final String TYPE_DATE = "date"; - public static final String TYPE_DATETIME = "datetime"; - - - private String id; //ID - private String label; //标题 - private String name; //组件的Name属性,若是以 article. 开头,则表示是文章的默认字段,否则是扩展字段 - private String placeholder; //占位符 - private String type; //类型 - private String value; //值,多个值用英文逗号隔开,checkbox、select 支持多个值 - private String valueText; //每个值对应的显示内容,例如 option 有 value 属性和其显示的具体内容 - private String helpText; //帮助文本内容 - private String attrs; //其他的属性,例如 "rows" = "3" - - private int orderNo; //排序字段 - private SmartFieldRender render; //自定义自己的render,自己没有render的时候,才会通过 SmartFieldRenderFactory 去获取 - - public SmartField() { - } - - public SmartField(String id, String label, String name, String placeholder, String type, String value, String valueText, String helpText, int orderNo) { - this.id = id; - this.label = label; - this.name = name; - this.placeholder = placeholder; - this.type = type; - this.value = value; - this.valueText = valueText; - this.helpText = helpText; - this.orderNo = orderNo; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPlaceholder() { - return placeholder; - } - - public void setPlaceholder(String placeholder) { - this.placeholder = placeholder; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getValue() { - return value == null ? "" : value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getValueText() { - return valueText; - } - - public void setValueText(String valueText) { - this.valueText = valueText; - } - - public String getHelpText() { - return helpText == null ? "" : helpText; - } - - public void setHelpText(String helpText) { - this.helpText = helpText; - } - - public String getAttrs() { - return attrs; - } - - public SmartField setAttrs(String attrs) { - this.attrs = attrs; - return this; - } - - public SmartField addAttr(String key, Object value) { - StringBuilder s = new StringBuilder() - .append(key) - .append("=\"") - .append(value.toString()) - .append("\" "); - this.attrs = this.attrs == null - ? s.toString() - : this.attrs + s.toString(); - return this; - } - - public int getOrderNo() { - return orderNo; - } - - public SmartField setOrderNo(int orderNo) { - this.orderNo = orderNo; - return this; - } - - public SmartFieldRender getRender() { - return render == null - ? SmartFieldRenderFactory.getRender(type) - : render; - } - - public SmartField setRender(SmartFieldRender render) { - this.render = render; - return this; - } - - public String render() { - if (StrUtil.isBlank(this.name)) { - return getRender().onRender(this, null); - } - - Object data = doGetDataFromControllerByName(this.name); - return getRender().onRender(this, data); - } - - public Object doGetDataFromControllerByName(String name) { - Controller controller = JbootControllerContext.get(); - if (name.contains(".")) { - String[] modelAndAttr = name.split("\\."); - String modelName = modelAndAttr[0]; - String attr = modelAndAttr[1]; - Object object = controller.getAttr(modelName); - if (object == null) { - return null; - } else if (object instanceof Model) { - return ((Model) object).get(attr); - } else if (object instanceof Map) { - return ((Map) object).get(attr); - } else { - try { - Method method = object.getClass().getMethod("get" + StrKit.firstCharToUpperCase(attr)); - return method.invoke(object); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - } else { - return controller.getAttr(name); - } - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield; + +import com.jfinal.core.Controller; +import com.jfinal.kit.StrKit; +import com.jfinal.plugin.activerecord.Model; +import io.jboot.utils.StrUtil; +import io.jboot.web.controller.JbootControllerContext; + +import java.lang.reflect.Method; +import java.util.Map; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: 文章字段 + */ +public class SmartField { + + public static final String TYPE_INPUT = "input"; + public static final String TYPE_TEXTAREA = "textarea"; + public static final String TYPE_SELECT = "select"; + public static final String TYPE_CHECKBOX = "checkbox"; + public static final String TYPE_SWITCH = "switch"; + public static final String TYPE_RADIO = "radio"; + public static final String TYPE_IMAGE = "image"; + public static final String TYPE_FILE = "file"; + public static final String TYPE_DATE = "date"; + public static final String TYPE_DATETIME = "datetime"; + + + private String id; //ID + private String label; //标题 + private String name; //组件的Name属性,若是以 article. 开头,则表示是文章的默认字段,否则是扩展字段 + private String placeholder; //占位符 + private String type; //类型 + private String value; //值,多个值用英文逗号隔开,checkbox、select 支持多个值 + private String valueText; //每个值对应的显示内容,例如 option 有 value 属性和其显示的具体内容 + private String helpText; //帮助文本内容 + private String attrs; //其他的属性,例如 "rows" = "3" + + private int orderNo; //排序字段 + private SmartFieldRender render; //自定义自己的render,自己没有render的时候,才会通过 SmartFieldRenderFactory 去获取 + + public SmartField() { + } + + public SmartField(String id, String label, String name, String placeholder, String type, String value, String valueText, String helpText, int orderNo) { + this.id = id; + this.label = label; + this.name = name; + this.placeholder = placeholder; + this.type = type; + this.value = value; + this.valueText = valueText; + this.helpText = helpText; + this.orderNo = orderNo; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPlaceholder() { + return placeholder; + } + + public void setPlaceholder(String placeholder) { + this.placeholder = placeholder; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value == null ? "" : value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getValueText() { + return valueText; + } + + public void setValueText(String valueText) { + this.valueText = valueText; + } + + public String getHelpText() { + return helpText == null ? "" : helpText; + } + + public void setHelpText(String helpText) { + this.helpText = helpText; + } + + public String getAttrs() { + return attrs; + } + + public SmartField setAttrs(String attrs) { + this.attrs = attrs; + return this; + } + + public SmartField addAttr(String key, Object value) { + StringBuilder s = new StringBuilder() + .append(key) + .append("=\"") + .append(value.toString()) + .append("\" "); + this.attrs = this.attrs == null + ? s.toString() + : this.attrs + s.toString(); + return this; + } + + public int getOrderNo() { + return orderNo; + } + + public SmartField setOrderNo(int orderNo) { + this.orderNo = orderNo; + return this; + } + + public SmartFieldRender getRender() { + return render == null + ? SmartFieldRenderFactory.getRender(type) + : render; + } + + public SmartField setRender(SmartFieldRender render) { + this.render = render; + return this; + } + + public String render() { + if (StrUtil.isBlank(this.name)) { + return getRender().onRender(this, null); + } + + Object data = doGetDataFromControllerByName(this.name); + return getRender().onRender(this, data); + } + + public Object doGetDataFromControllerByName(String name) { + Controller controller = JbootControllerContext.get(); + if (name.contains(".")) { + String[] modelAndAttr = name.split("\\."); + String modelName = modelAndAttr[0]; + String attr = modelAndAttr[1]; + Object object = controller.getAttr(modelName); + if (object == null) { + return null; + } else if (object instanceof Model) { + return ((Model) object).get(attr); + } else if (object instanceof Map) { + return ((Map) object).get(attr); + } else { + try { + Method method = object.getClass().getMethod("get" + StrKit.firstCharToUpperCase(attr)); + return method.invoke(object); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + } else { + return controller.getAttr(name); + } + } + + +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartFieldRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartFieldRender.java index d2deec66b26f7bd49db2d319126ff47579d8137f..ba452b27164dcaa5b3f6bd41df4dd6a15a764ea5 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartFieldRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartFieldRender.java @@ -1,26 +1,26 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Field 渲染器,目的是生成 html 的内容 - */ -public interface SmartFieldRender { - - public String onRender(SmartField field, Object value); -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Field 渲染器,目的是生成 html 的内容 + */ +public interface SmartFieldRender { + + public String onRender(SmartField field, Object value); +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartFieldRenderFactory.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartFieldRenderFactory.java index f07232103245ac7152ec2046f0dfb3016aa8003c..7030b9349eb0f63d1ece6f1e5642195187a942cb 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartFieldRenderFactory.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/SmartFieldRenderFactory.java @@ -1,58 +1,58 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield; - - -import io.jpress.core.support.smartfield.renders.*; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Field 渲染器,目的是生成 html 的内容 - */ -public class SmartFieldRenderFactory { - - private static Map renderMap = new ConcurrentHashMap<>(); - - static { - registerRender(SmartField.TYPE_INPUT, new InputRender()); - registerRender(SmartField.TYPE_TEXTAREA, new TextareaRender()); - registerRender(SmartField.TYPE_SELECT, new SelectRender()); - registerRender(SmartField.TYPE_CHECKBOX, new CheckboxRender()); - registerRender(SmartField.TYPE_SWITCH, new SwitchRender()); - registerRender(SmartField.TYPE_RADIO, new RadioRender()); - registerRender(SmartField.TYPE_IMAGE, new ImageRender()); - registerRender(SmartField.TYPE_FILE, new FileRender()); - registerRender(SmartField.TYPE_DATE, new DateRender()); - registerRender(SmartField.TYPE_DATETIME, new DatetimeRender()); - } - - - public static void registerRender(String type, SmartFieldRender render) { - renderMap.put(type, render); - } - - public static SmartFieldRender getRender(String type) { - return renderMap.get(type); - } - - public static Map getRenderMap() { - return renderMap; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield; + + +import io.jpress.core.support.smartfield.renders.*; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Field 渲染器,目的是生成 html 的内容 + */ +public class SmartFieldRenderFactory { + + private static Map renderMap = new ConcurrentHashMap<>(); + + static { + registerRender(SmartField.TYPE_INPUT, new InputRender()); + registerRender(SmartField.TYPE_TEXTAREA, new TextareaRender()); + registerRender(SmartField.TYPE_SELECT, new SelectRender()); + registerRender(SmartField.TYPE_CHECKBOX, new CheckboxRender()); + registerRender(SmartField.TYPE_SWITCH, new SwitchRender()); + registerRender(SmartField.TYPE_RADIO, new RadioRender()); + registerRender(SmartField.TYPE_IMAGE, new ImageRender()); + registerRender(SmartField.TYPE_FILE, new FileRender()); + registerRender(SmartField.TYPE_DATE, new DateRender()); + registerRender(SmartField.TYPE_DATETIME, new DatetimeRender()); + } + + + public static void registerRender(String type, SmartFieldRender render) { + renderMap.put(type, render); + } + + public static SmartFieldRender getRender(String type) { + return renderMap.get(type); + } + + public static Map getRenderMap() { + return renderMap; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/CheckboxRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/CheckboxRender.java index 6d3f8a80d71f54b97ac054b5ebba2963bf7c6719..e00a0f6aff0df35b1cf2e3cc1d362f6c9469ef30 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/CheckboxRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/CheckboxRender.java @@ -1,92 +1,92 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jboot.utils.StrUtil; -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -import java.util.Objects; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Textarea 的渲染器 - */ -public class CheckboxRender implements SmartFieldRender { - - protected static String template1 = "" + - "

    \n" + - " "; - - - protected static String template_item = "" + - "
    \n" + - "
    \n" + - " \n" + - "
    \n" + - "
    "; - - - protected static String template2 = "
    "; - - @Override - public String onRender(SmartField field, Object value) { - if (StrUtil.isBlank(field.getValue())) { - return null; - } - - String[] values = field.getValue().split(","); - String[] texts = StrUtil.isBlank(field.getValueText()) ? values : field.getValueText().split(","); - - String[] dbValues = (value == null) ? null : value.toString().split(","); - - int index = 0; - StringBuilder items = new StringBuilder(); - for (String v : values) { - String item = template_item.replace("{offset}", index == 0 ? "" : "col-sm-offset-2") - .replace("{text}", getText(texts, index++, v)) - .replace("{checked}", getCheckedText(v, dbValues)) - .replace("{name}", field.getName()) - .replace("{value}", v); - items.append(item); - } - - return RenderKit.replace(template1, "{label}", field.getLabel()) + - items.toString() + template2; - } - - private String getCheckedText(String v, String[] values) { - if (values == null) { - return StrUtil.EMPTY; - } - for (String value : values) { - if (Objects.equals(v, value)) { - return "checked"; - } - } - return StrUtil.EMPTY; - } - - private String getText(String[] texts, int i, String v) { - if (texts != null && texts.length > i) { - return texts[i]; - } - return v; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jboot.utils.StrUtil; +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +import java.util.Objects; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Textarea 的渲染器 + */ +public class CheckboxRender implements SmartFieldRender { + + protected static String template1 = "" + + "

    \n" + + " "; + + + protected static String template_item = "" + + "
    \n" + + "
    \n" + + " \n" + + "
    \n" + + "
    "; + + + protected static String template2 = "
    "; + + @Override + public String onRender(SmartField field, Object value) { + if (StrUtil.isBlank(field.getValue())) { + return null; + } + + String[] values = field.getValue().split(","); + String[] texts = StrUtil.isBlank(field.getValueText()) ? values : field.getValueText().split(","); + + String[] dbValues = (value == null) ? null : value.toString().split(","); + + int index = 0; + StringBuilder items = new StringBuilder(); + for (String v : values) { + String item = template_item.replace("{offset}", index == 0 ? "" : "col-sm-offset-2") + .replace("{text}", getText(texts, index++, v)) + .replace("{checked}", getCheckedText(v, dbValues)) + .replace("{name}", field.getName()) + .replace("{value}", v); + items.append(item); + } + + return RenderKit.replace(template1, "{label}", field.getLabel()) + + items.toString() + template2; + } + + private String getCheckedText(String v, String[] values) { + if (values == null) { + return StrUtil.EMPTY; + } + for (String value : values) { + if (Objects.equals(v, value)) { + return "checked"; + } + } + return StrUtil.EMPTY; + } + + private String getText(String[] texts, int i, String v) { + if (texts != null && texts.length > i) { + return texts[i]; + } + return v; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/DateRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/DateRender.java index c7fca68d9109db2389b481ebb8fd09911387bbd2..16d76560fbf6aa044ecc0fb77c566052803e4a05 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/DateRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/DateRender.java @@ -1,46 +1,46 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Input 输入框的渲染器 - */ -public class DateRender implements SmartFieldRender { - - protected static String template = "" + - "

    \n" + - " \n" + - "
    \n" + - " \n" + - "

    {helpText}

    \n" + - "
    \n" + - "
    "; - - @Override - public String onRender(SmartField field, Object value) { - return RenderKit.render(template, field, value); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Input 输入框的渲染器 + */ +public class DateRender implements SmartFieldRender { + + protected static String template = "" + + "

    \n" + + " \n" + + "
    \n" + + " \n" + + "

    {helpText}

    \n" + + "
    \n" + + "
    "; + + @Override + public String onRender(SmartField field, Object value) { + return RenderKit.render(template, field, value); + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/DatetimeRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/DatetimeRender.java index 662439ce39e6662a710d6107d7db648154f7a51d..9f65d8c8c8b5892d829d3186c4c1b65abcb12fb9 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/DatetimeRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/DatetimeRender.java @@ -1,46 +1,46 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Datetime 时间选择器的渲染器 - */ -public class DatetimeRender implements SmartFieldRender { - - protected static String template = "" + - "

    \n" + - " \n" + - "
    \n" + - " \n" + - "

    {helpText}

    \n" + - "
    \n" + - "
    "; - - @Override - public String onRender(SmartField field, Object value) { - return RenderKit.render(template, field, value); - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Datetime 时间选择器的渲染器 + */ +public class DatetimeRender implements SmartFieldRender { + + protected static String template = "" + + "

    \n" + + " \n" + + "
    \n" + + " \n" + + "

    {helpText}

    \n" + + "
    \n" + + "
    "; + + @Override + public String onRender(SmartField field, Object value) { + return RenderKit.render(template, field, value); + } + + +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/FileRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/FileRender.java index b8f7e672bcb718b51228ad9b365e6a75996b5ab0..c3212f4495ad2536dcffa70340b6ae0f982b594a 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/FileRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/FileRender.java @@ -1,33 +1,33 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Input 输入框的渲染器 - */ -public class FileRender implements SmartFieldRender { - - @Override - public String onRender(SmartField field, Object value) { - throw new IllegalStateException("FileRender not finished."); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Input 输入框的渲染器 + */ +public class FileRender implements SmartFieldRender { + + @Override + public String onRender(SmartField field, Object value) { + throw new IllegalStateException("FileRender not finished."); + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/ImageRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/ImageRender.java index dbacdac4c700f7540e6fbc0ff57b1dc289d46f0a..94ec32d95a514cd60ce0ecbef3d0e088ff6ea85e 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/ImageRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/ImageRender.java @@ -1,34 +1,34 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Input 输入框的渲染器 - */ -public class ImageRender implements SmartFieldRender { - - - @Override - public String onRender(SmartField field, Object value) { - throw new IllegalStateException("ImageRender not finished."); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Input 输入框的渲染器 + */ +public class ImageRender implements SmartFieldRender { + + + @Override + public String onRender(SmartField field, Object value) { + throw new IllegalStateException("ImageRender not finished."); + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/InputRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/InputRender.java index 74e2b104f2559f0caacd97b370dac9e6a8cd0220..cd784f0c70585b17c59439aa85db801e0266d039 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/InputRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/InputRender.java @@ -1,45 +1,45 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Input 输入框的渲染器 - */ -public class InputRender implements SmartFieldRender { - - protected static String template = "" + - "

    \n" + - " \n" + - "
    \n" + - " \n" + - "

    {helpText}

    \n" + - "
    \n" + - "
    "; - - @Override - public String onRender(SmartField field, Object value) { - return RenderKit.render(template, field, value); - } - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Input 输入框的渲染器 + */ +public class InputRender implements SmartFieldRender { + + protected static String template = "" + + "

    \n" + + " \n" + + "
    \n" + + " \n" + + "

    {helpText}

    \n" + + "
    \n" + + "
    "; + + @Override + public String onRender(SmartField field, Object value) { + return RenderKit.render(template, field, value); + } + +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/RadioRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/RadioRender.java index a993be84b10a3e3299b37b3831bf20f7999d25f7..d9fd1444b62215bd7a81ec21bff140349f1f374b 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/RadioRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/RadioRender.java @@ -1,83 +1,83 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jboot.utils.StrUtil; -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -import java.util.Objects; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Input 输入框的渲染器 - */ -public class RadioRender implements SmartFieldRender { - - protected static String template1 = "" + - "

    \n" + - " "; - - - protected static String template_item = "" + - "
    \n" + - "
    \n" + - " \n" + - "
    \n" + - "
    "; - - - protected static String template2 = "
    "; - - @Override - public String onRender(SmartField field, Object value) { - if (StrUtil.isBlank(field.getValue())) { - return null; - } - - String[] values = field.getValue().split(","); - String[] texts = StrUtil.isBlank(field.getValueText()) ? values : field.getValueText().split(","); - - - int index = 0; - StringBuilder items = new StringBuilder(); - for (String v : values) { - String item = template_item.replace("{offset}", index == 0 ? "" : "col-sm-offset-2") - .replace("{text}", getText(texts, index++, v)) - .replace("{checked}", getCheckedText(v, value)) - .replace("{name}", field.getName()) - .replace("{value}",v); - items.append(item); - } - - return RenderKit.replace(template1, "{label}", field.getLabel()) + - items.toString() + template2; - } - - private String getCheckedText(String v, Object value) { - return Objects.equals(v, value) ? "checked" : ""; - } - - private String getText(String[] texts, int i, String v) { - if (texts != null && texts.length > i) { - return texts[i]; - } - return v; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jboot.utils.StrUtil; +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +import java.util.Objects; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Input 输入框的渲染器 + */ +public class RadioRender implements SmartFieldRender { + + protected static String template1 = "" + + "

    \n" + + " "; + + + protected static String template_item = "" + + "
    \n" + + "
    \n" + + " \n" + + "
    \n" + + "
    "; + + + protected static String template2 = "
    "; + + @Override + public String onRender(SmartField field, Object value) { + if (StrUtil.isBlank(field.getValue())) { + return null; + } + + String[] values = field.getValue().split(","); + String[] texts = StrUtil.isBlank(field.getValueText()) ? values : field.getValueText().split(","); + + + int index = 0; + StringBuilder items = new StringBuilder(); + for (String v : values) { + String item = template_item.replace("{offset}", index == 0 ? "" : "col-sm-offset-2") + .replace("{text}", getText(texts, index++, v)) + .replace("{checked}", getCheckedText(v, value)) + .replace("{name}", field.getName()) + .replace("{value}",v); + items.append(item); + } + + return RenderKit.replace(template1, "{label}", field.getLabel()) + + items.toString() + template2; + } + + private String getCheckedText(String v, Object value) { + return Objects.equals(v, value) ? "checked" : ""; + } + + private String getText(String[] texts, int i, String v) { + if (texts != null && texts.length > i) { + return texts[i]; + } + return v; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/RenderKit.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/RenderKit.java index 9ac92c403f3f1411b3db19badc9924c85819f069..c7729867828fca7431e91c089c7f81435c23eea6 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/RenderKit.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/RenderKit.java @@ -1,43 +1,43 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jboot.utils.StrUtil; -import io.jpress.core.support.smartfield.SmartField; - - -public class RenderKit { - - public static String render(String template, SmartField field, Object value) { - if (StrUtil.isBlank(template)) { - return template; - } - - template = replace(template, "{label}", field.getLabel()); - template = replace(template, "{id}", field.getId()); - template = replace(template, "{name}", field.getName()); - template = replace(template, "{placeholder}", field.getPlaceholder()); - template = replace(template, "{value}", value == null ? field.getValue() : value); - template = replace(template, "{helpText}", field.getHelpText()); - template = replace(template, "{attrs}", field.getAttrs()); - - return template; - } - - public static String replace(String template, String target, Object content) { - return template.replace(target, content == null ? StrUtil.EMPTY : content.toString()); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jboot.utils.StrUtil; +import io.jpress.core.support.smartfield.SmartField; + + +public class RenderKit { + + public static String render(String template, SmartField field, Object value) { + if (StrUtil.isBlank(template)) { + return template; + } + + template = replace(template, "{label}", field.getLabel()); + template = replace(template, "{id}", field.getId()); + template = replace(template, "{name}", field.getName()); + template = replace(template, "{placeholder}", field.getPlaceholder()); + template = replace(template, "{value}", value == null ? field.getValue() : value); + template = replace(template, "{helpText}", field.getHelpText()); + template = replace(template, "{attrs}", field.getAttrs()); + + return template; + } + + public static String replace(String template, String target, Object content) { + return template.replace(target, content == null ? StrUtil.EMPTY : content.toString()); + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/SelectRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/SelectRender.java index 4813b26751ccf9d29c4671ee68ee42d3576feadf..054bf208adfcb6f47d97bdf676082b07c62292b3 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/SelectRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/SelectRender.java @@ -1,83 +1,83 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jboot.utils.StrUtil; -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -import java.util.Objects; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Textarea 的渲染器 - */ -public class SelectRender implements SmartFieldRender { - - protected static String template1 = "" + - "

    \n" + - " \n" + - "
    \n" + - " \n" + - "

    {helpText}

    \n" + - "
    \n" + - "
    "; - - @Override - public String onRender(SmartField field, Object value) { - if (StrUtil.isBlank(field.getValue())) { - return null; - } - - String[] values = field.getValue().split(","); - String[] texts = StrUtil.isBlank(field.getValueText()) ? values : field.getValueText().split(","); - - - int index = 0; - StringBuilder options = new StringBuilder(); - for (String v : values) { - options.append("\n"); - } - - return RenderKit.render(template1, field, value) + - options.toString() + - RenderKit.render(template2, field, value); - } - - private String getSelectedText(String v, Object value) { - return Objects.equals(v, value) ? "selected" : ""; - } - - private String getText(String[] texts, int i, String v) { - if (texts != null && texts.length > i) { - return texts[i]; - } - return v; - } - - -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jboot.utils.StrUtil; +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +import java.util.Objects; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Textarea 的渲染器 + */ +public class SelectRender implements SmartFieldRender { + + protected static String template1 = "" + + "

    \n" + + " \n" + + "
    \n" + + " \n" + + "

    {helpText}

    \n" + + "
    \n" + + "
    "; + + @Override + public String onRender(SmartField field, Object value) { + if (StrUtil.isBlank(field.getValue())) { + return null; + } + + String[] values = field.getValue().split(","); + String[] texts = StrUtil.isBlank(field.getValueText()) ? values : field.getValueText().split(","); + + + int index = 0; + StringBuilder options = new StringBuilder(); + for (String v : values) { + options.append("\n"); + } + + return RenderKit.render(template1, field, value) + + options.toString() + + RenderKit.render(template2, field, value); + } + + private String getSelectedText(String v, Object value) { + return Objects.equals(v, value) ? "selected" : ""; + } + + private String getText(String[] texts, int i, String v) { + if (texts != null && texts.length > i) { + return texts[i]; + } + return v; + } + + +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/SwitchRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/SwitchRender.java index 0f8342ea390512a1d200f71ff0ae1dc52ea97dd0..08b5664e6ab7c2c72b968a36b9b8a8ce16998347 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/SwitchRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/SwitchRender.java @@ -1,48 +1,48 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -import java.util.Objects; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Switch 的渲染器 - */ -public class SwitchRender implements SmartFieldRender { - - protected static String template = "" + - "

    \n" + - " \n" + - "
    \n" + - " \n" + - "

    {helpText}

    \n" + - " \n" + - "
    \n" + - "
    "; - - @Override - public String onRender(SmartField field, Object value) { - String checked = (value == null && "true".equals(field.getValue())) - ? "checked" - : (Objects.equals("true", String.valueOf(value)) ? "checked" : ""); - return RenderKit.render(template, field, value).replace("{checked}", checked); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +import java.util.Objects; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Switch 的渲染器 + */ +public class SwitchRender implements SmartFieldRender { + + protected static String template = "" + + "

    \n" + + " \n" + + "
    \n" + + " \n" + + "

    {helpText}

    \n" + + " \n" + + "
    \n" + + "
    "; + + @Override + public String onRender(SmartField field, Object value) { + String checked = (value == null && "true".equals(field.getValue())) + ? "checked" + : (Objects.equals("true", String.valueOf(value)) ? "checked" : ""); + return RenderKit.render(template, field, value).replace("{checked}", checked); + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/TextareaRender.java b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/TextareaRender.java index 1df5743005be1604f6d46a17e0f9a36f11f0cb5b..293c6c91598417b412a1d2033bd66a84e747a18b 100644 --- a/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/TextareaRender.java +++ b/jpress-core/src/main/java/io/jpress/core/support/smartfield/renders/TextareaRender.java @@ -1,44 +1,44 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.support.smartfield.renders; - -import io.jpress.core.support.smartfield.SmartField; -import io.jpress.core.support.smartfield.SmartFieldRender; - -/** - * @author Michael Yang 杨福海 (fuhai999@gmail.com) - * @version V1.0 - * @Title: Textarea 的渲染器 - */ -public class TextareaRender implements SmartFieldRender { - - protected static String template = "" + - "

    \n" + - "\n" + - "
    \n" + - " \n" + - "

    {helpText}

    \n" + - "
    \n" + - "
    "; - - @Override - public String onRender(SmartField field, Object value) { - return RenderKit.render(template, field, value); - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.support.smartfield.renders; + +import io.jpress.core.support.smartfield.SmartField; +import io.jpress.core.support.smartfield.SmartFieldRender; + +/** + * @author Michael Yang 杨福海 (fuhai999@gmail.com) + * @version V1.0 + * @Title: Textarea 的渲染器 + */ +public class TextareaRender implements SmartFieldRender { + + protected static String template = "" + + "

    \n" + + "\n" + + "
    \n" + + " \n" + + "

    {helpText}

    \n" + + "
    \n" + + "
    "; + + @Override + public String onRender(SmartField field, Object value) { + return RenderKit.render(template, field, value); + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/template/Template.java b/jpress-core/src/main/java/io/jpress/core/template/Template.java index f2643bbfef0ccd4b2ab5ec96de333a017a88d004..f85ee5c379a90a61f9f03295e15840e5243f047f 100644 --- a/jpress-core/src/main/java/io/jpress/core/template/Template.java +++ b/jpress-core/src/main/java/io/jpress/core/template/Template.java @@ -1,325 +1,325 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.template; - -import com.jfinal.kit.PathKit; -import com.jfinal.kit.Prop; -import io.jboot.utils.FileUtil; -import io.jboot.utils.StrUtil; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.StringUtils; - -import java.io.File; -import java.util.*; - -public class Template { - - private String id; - private String title; - private String description; - private String author; - private String authorWebsite; - private String version; - private int versionCode; - private String updateUrl; - private String screenshot; - - private String relativePath; - - private Set htmls = new HashSet<>(); - private List flags = new ArrayList<>(); - - public Template() { - - } - - public Template(File templateFolder) { - - File propFile = new File(templateFolder, "template.properties"); - Prop prop = new Prop(propFile, "utf-8"); - - this.id = prop.get("id"); - this.title = prop.get("title"); - this.description = prop.get("description"); - this.author = prop.get("author"); - this.authorWebsite = prop.get("authorWebsite"); - this.version = prop.get("version"); - this.updateUrl = prop.get("updateUrl"); - - this.relativePath = FileUtil.removeRootPath(templateFolder.getAbsolutePath()).replace("\\", "/"); - - String vcode = prop.get("versionCode"); - this.versionCode = StrUtil.isBlank(vcode) ? 1 : Integer.valueOf(vcode); - this.screenshot = relativePath + "/screenshot.png"; - - refresh(); - } - - - public void refresh() { - - this.htmls.clear(); - this.flags.clear(); - - File path = getAbsolutePathFile(); - Prop prop = new Prop(new File(path, "template.properties"), "utf-8"); - - String[] files = path - .list((dir, name) -> name.endsWith(".html")); - - if (files != null && files.length > 0) { - this.htmls.addAll(Arrays.asList(files)); - } - - String flagStrings = prop.get("flags"); - if (StrUtil.isNotBlank(flagStrings)) { - this.flags.addAll(StrUtil.splitToSet(flagStrings, ",")); - } - } - - - private static final String TEMPLATE_SEPARATOR = "_"; - private static final String TEMPLATE_H5_SUFFIX = "_h5.html"; - - /** - * 找出可以用来渲染的 html 模板 - * - * @param template - * @return - */ - public String matchView(String template, boolean isMoblieBrowser) { - - if (isMoblieBrowser) { - int indexOf = template.indexOf("."); - template = template.substring(0, indexOf) + TEMPLATE_H5_SUFFIX; - } - - if (htmls.contains(template)) { - return template; - } - - int lastIndex = template.lastIndexOf(TEMPLATE_SEPARATOR); - if (lastIndex <= 0) { - return null; - } - - //手机浏览器,优先去找_h5的模板进行渲染 - if (isMoblieBrowser) { - String h5Template = matchH5Template(template); - if (h5Template != null) { - return h5Template; - } - } - - while (lastIndex > 0) { - template = template.substring(0, lastIndex) + ".html"; - if (htmls.contains(template)) { - return template; - } - lastIndex = template.lastIndexOf(TEMPLATE_SEPARATOR); - } - - return htmls.contains(template) ? template : null; - } - - - /** - * 只匹配 h5 的模板 ,如果匹配不到 h5 ,返回 null - *

    - * 例如: - * 需要 aa_bb_cc_dd_h5.html - * 寻找的顺序是:aa_bb_cc_h5.html -> aa_bb_h5.html -> aa_h5.html - * - * @param template - * @return - */ - private String matchH5Template(String template) { - - while (StringUtils.countMatches(template, '_') > 1) { - - int sLastIndex = StringUtils.lastOrdinalIndexOf(template, "_", 2); - template = template.substring(0, sLastIndex) + "_h5.html"; - - if (htmls.contains(template)) { - return template; - } - } - - return htmls.contains(template) ? template : null; - } - - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public String getAuthorWebsite() { - return authorWebsite; - } - - public void setAuthorWebsite(String authorWebsite) { - this.authorWebsite = authorWebsite; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public int getVersionCode() { - return versionCode; - } - - public void setVersionCode(int versionCode) { - this.versionCode = versionCode; - } - - public String getUpdateUrl() { - return updateUrl; - } - - public void setUpdateUrl(String updateUrl) { - this.updateUrl = updateUrl; - } - - - public String getScreenshot() { - return screenshot; - } - - public void setScreenshot(String screenshot) { - this.screenshot = screenshot; - } - - public String getRelativePath() { - return relativePath; - } - - public void setRelativePath(String relativePath) { - this.relativePath = relativePath; - } - - public List getFlags() { - return flags; - } - - public void setFlags(List flags) { - this.flags = flags; - } - - - public String buildRelativePath(String html) { - return new StringBuilder(relativePath).append("/").append(html).toString(); - } - - /** - * 获得某个模块下支持的样式 - * 一般用于在后台设置 - * - * @param prefix - * @return - */ - public List getSupportStyles(String prefix) { - - if (prefix == null) { - throw new IllegalArgumentException("prefix must not be null"); - } - - List styles = new ArrayList<>(); - for (String html : htmls) { - //xxx_h5.html 不算独立样式 - if (html.startsWith(prefix) && !html.contains("_h5.")) { - styles.add(html.substring(prefix.length(), html.length() - 5)); - } - } - - return styles; - } - - /** - * 卸载模板 - */ - public void uninstall() { - StringBuilder newFileName = new StringBuilder(PathKit.getWebRootPath()); - newFileName.append(File.separator); - newFileName.append("templates"); - newFileName.append(File.separator); - newFileName.append("dockers"); - File templateRootPath = new File(newFileName.toString()); - - File delPath = findInstallPath(templateRootPath,getAbsolutePathFile()); - FileUtils.deleteQuietly(delPath); - } - - - private File findInstallPath(File templateRootPath,File file) { - File parent = file.getParentFile(); - if (parent.getAbsolutePath().equals(templateRootPath.getAbsolutePath()) - || parent.getAbsolutePath().equals(templateRootPath.getParentFile().getAbsolutePath())) { - return file; - } - - return findInstallPath(templateRootPath,file.getParentFile()); - } - - public File getAbsolutePathFile() { - return new File(PathKit.getWebRootPath(), relativePath); - } - - - public void addNewHtml(String htmlFileName) { - htmls.add(htmlFileName); - } - - public void deleteHtml(String htmlFileName) { - htmls.remove(htmlFileName); - } - - public Set getHtmls() { - return htmls; - } -} +/** + * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). + *

    + * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

    + * http://www.gnu.org/licenses/lgpl-3.0.txt + *

    + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jpress.core.template; + +import com.jfinal.kit.PathKit; +import com.jfinal.kit.Prop; +import io.jboot.utils.FileUtil; +import io.jboot.utils.StrUtil; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.util.*; + +public class Template { + + private String id; + private String title; + private String description; + private String author; + private String authorWebsite; + private String version; + private int versionCode; + private String updateUrl; + private String screenshot; + + private String relativePath; + + private Set htmls = new HashSet<>(); + private List flags = new ArrayList<>(); + + public Template() { + + } + + public Template(File templateFolder) { + + File propFile = new File(templateFolder, "template.properties"); + Prop prop = new Prop(propFile, "utf-8"); + + this.id = prop.get("id"); + this.title = prop.get("title"); + this.description = prop.get("description"); + this.author = prop.get("author"); + this.authorWebsite = prop.get("authorWebsite"); + this.version = prop.get("version"); + this.updateUrl = prop.get("updateUrl"); + + this.relativePath = FileUtil.removeRootPath(templateFolder.getAbsolutePath()).replace("\\", "/"); + + String vcode = prop.get("versionCode"); + this.versionCode = StrUtil.isBlank(vcode) ? 1 : Integer.valueOf(vcode); + this.screenshot = relativePath + "/screenshot.png"; + + refresh(); + } + + + public void refresh() { + + this.htmls.clear(); + this.flags.clear(); + + File path = getAbsolutePathFile(); + Prop prop = new Prop(new File(path, "template.properties"), "utf-8"); + + String[] files = path + .list((dir, name) -> name.endsWith(".html")); + + if (files != null && files.length > 0) { + this.htmls.addAll(Arrays.asList(files)); + } + + String flagStrings = prop.get("flags"); + if (StrUtil.isNotBlank(flagStrings)) { + this.flags.addAll(StrUtil.splitToSet(flagStrings, ",")); + } + } + + + private static final String TEMPLATE_SEPARATOR = "_"; + private static final String TEMPLATE_H5_SUFFIX = "_h5.html"; + + /** + * 找出可以用来渲染的 html 模板 + * + * @param template + * @return + */ + public String matchView(String template, boolean isMoblieBrowser) { + + if (isMoblieBrowser) { + int indexOf = template.indexOf("."); + template = template.substring(0, indexOf) + TEMPLATE_H5_SUFFIX; + } + + if (htmls.contains(template)) { + return template; + } + + int lastIndex = template.lastIndexOf(TEMPLATE_SEPARATOR); + if (lastIndex <= 0) { + return null; + } + + //手机浏览器,优先去找_h5的模板进行渲染 + if (isMoblieBrowser) { + String h5Template = matchH5Template(template); + if (h5Template != null) { + return h5Template; + } + } + + while (lastIndex > 0) { + template = template.substring(0, lastIndex) + ".html"; + if (htmls.contains(template)) { + return template; + } + lastIndex = template.lastIndexOf(TEMPLATE_SEPARATOR); + } + + return htmls.contains(template) ? template : null; + } + + + /** + * 只匹配 h5 的模板 ,如果匹配不到 h5 ,返回 null + *

    + * 例如: + * 需要 aa_bb_cc_dd_h5.html + * 寻找的顺序是:aa_bb_cc_h5.html -> aa_bb_h5.html -> aa_h5.html + * + * @param template + * @return + */ + private String matchH5Template(String template) { + + while (StringUtils.countMatches(template, '_') > 1) { + + int sLastIndex = StringUtils.lastOrdinalIndexOf(template, "_", 2); + template = template.substring(0, sLastIndex) + "_h5.html"; + + if (htmls.contains(template)) { + return template; + } + } + + return htmls.contains(template) ? template : null; + } + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAuthorWebsite() { + return authorWebsite; + } + + public void setAuthorWebsite(String authorWebsite) { + this.authorWebsite = authorWebsite; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public int getVersionCode() { + return versionCode; + } + + public void setVersionCode(int versionCode) { + this.versionCode = versionCode; + } + + public String getUpdateUrl() { + return updateUrl; + } + + public void setUpdateUrl(String updateUrl) { + this.updateUrl = updateUrl; + } + + + public String getScreenshot() { + return screenshot; + } + + public void setScreenshot(String screenshot) { + this.screenshot = screenshot; + } + + public String getRelativePath() { + return relativePath; + } + + public void setRelativePath(String relativePath) { + this.relativePath = relativePath; + } + + public List getFlags() { + return flags; + } + + public void setFlags(List flags) { + this.flags = flags; + } + + + public String buildRelativePath(String html) { + return new StringBuilder(relativePath).append("/").append(html).toString(); + } + + /** + * 获得某个模块下支持的样式 + * 一般用于在后台设置 + * + * @param prefix + * @return + */ + public List getSupportStyles(String prefix) { + + if (prefix == null) { + throw new IllegalArgumentException("prefix must not be null"); + } + + List styles = new ArrayList<>(); + for (String html : htmls) { + //xxx_h5.html 不算独立样式 + if (html.startsWith(prefix) && !html.contains("_h5.")) { + styles.add(html.substring(prefix.length(), html.length() - 5)); + } + } + + return styles; + } + + /** + * 卸载模板 + */ + public void uninstall() { + StringBuilder newFileName = new StringBuilder(PathKit.getWebRootPath()); + newFileName.append(File.separator); + newFileName.append("templates"); + newFileName.append(File.separator); + newFileName.append("dockers"); + File templateRootPath = new File(newFileName.toString()); + + File delPath = findInstallPath(templateRootPath,getAbsolutePathFile()); + FileUtils.deleteQuietly(delPath); + } + + + private File findInstallPath(File templateRootPath,File file) { + File parent = file.getParentFile(); + if (parent.getAbsolutePath().equals(templateRootPath.getAbsolutePath()) + || parent.getAbsolutePath().equals(templateRootPath.getParentFile().getAbsolutePath())) { + return file; + } + + return findInstallPath(templateRootPath,file.getParentFile()); + } + + public File getAbsolutePathFile() { + return new File(PathKit.getWebRootPath(), relativePath); + } + + + public void addNewHtml(String htmlFileName) { + htmls.add(htmlFileName); + } + + public void deleteHtml(String htmlFileName) { + htmls.remove(htmlFileName); + } + + public Set getHtmls() { + return htmls; + } +} diff --git a/jpress-core/src/main/java/io/jpress/core/template/TemplateManager.java b/jpress-core/src/main/java/io/jpress/core/template/TemplateManager.java index 5e33cd3858f2c8fe11d56d228df74118e7ebeb13..b430dd6567df1640a82f1398eea612e52c29af69 100644 --- a/jpress-core/src/main/java/io/jpress/core/template/TemplateManager.java +++ b/jpress-core/src/main/java/io/jpress/core/template/TemplateManager.java @@ -1,195 +1,195 @@ -/** - * Copyright (c) 2016-2020, Michael Yang 杨福海 (fuhai999@gmail.com). - *

    - * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

    - * http://www.gnu.org/licenses/lgpl-3.0.txt - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jpress.core.template; - -import com.jfinal.core.Controller; -import com.jfinal.kit.LogKit; -import com.jfinal.kit.PathKit; -import com.jfinal.render.RenderManager; -import io.jboot.utils.StrUtil; -import io.jboot.web.controller.JbootControllerContext; -import io.jpress.JPressConfig; -import io.jpress.JPressOptions; -import io.jpress.commons.CacheObject; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -public class TemplateManager { - - private Template currentTemplate; - private CacheObject currentTemplateId = new CacheObject("template", "id"); - private TemplateNotifier notifier; - - private static final TemplateManager me = new TemplateManager(); - - private TemplateManager() { - - } - - - public static TemplateManager me() { - return me; - } - - - public void init() { - String templateId = JPressOptions.get("web_template"); - TemplateManager.me().initDefaultTemplate(templateId); - } - - - public List