Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef4d06ff2e | ||
|
|
24d51e416e | ||
|
|
ed836c2f6a | ||
|
|
529d2b8192 | ||
|
|
9c0885b4c9 | ||
|
|
7ccbb05b7b | ||
|
|
53af15f85d | ||
|
|
21b15f16e3 | ||
|
|
8176853791 | ||
|
|
a56e29d8f7 | ||
|
|
081505f79c | ||
|
|
a6adfbc726 | ||
|
|
e883de354f | ||
|
|
f4909921ac | ||
|
|
0eb09a0dbb | ||
|
|
a58a2dcda2 | ||
|
|
1318ce840c | ||
|
|
0a771a7008 | ||
|
|
2ea481a417 | ||
|
|
07d3eef8ab | ||
|
|
f3c4a0dbe9 | ||
|
|
8f14549fee | ||
|
|
bccecc8b39 | ||
|
|
4a8bad7d35 | ||
|
|
8ef29563f5 | ||
|
|
87b8dc6ec4 | ||
|
|
b1f29a9d57 | ||
|
|
33eb95f120 | ||
|
|
4bfe7b2316 | ||
|
|
b0350b36d7 | ||
|
|
9f16332c09 | ||
|
|
419ed4f01b | ||
|
|
69cd032b7e | ||
|
|
c0aeef4881 | ||
|
|
e7c6e7e85b | ||
|
|
7f06df2bed | ||
|
|
250788a398 | ||
|
|
196cf4f10c | ||
|
|
3b587c661b | ||
|
|
7eb9484d7e | ||
|
|
c610af7c6b | ||
|
|
0c7cefb184 | ||
|
|
19d2399eb2 | ||
|
|
37b0a120c9 | ||
|
|
5fb6ab0ca6 | ||
|
|
2ba8b953d3 | ||
|
|
738fd5c552 | ||
|
|
745f6e88c0 | ||
|
|
3db837d6d6 | ||
|
|
14054a964f | ||
|
|
14581655d2 | ||
|
|
f162584d1e | ||
|
|
e57e8127b5 | ||
|
|
b7d4efa6a6 | ||
|
|
91a4db4eb8 | ||
|
|
7ed84e48cf | ||
|
|
f068bd9c90 | ||
|
|
4ae907a023 | ||
|
|
652a242c2b | ||
|
|
d242408de2 | ||
|
|
b8f51011ed | ||
|
|
84913ab783 | ||
|
|
b7bb765193 | ||
|
|
d1b06c45c8 | ||
|
|
19fe2023a6 | ||
|
|
590046d90c | ||
|
|
00c162ece1 | ||
|
|
d5deb38769 | ||
|
|
b71165f73c | ||
|
|
4260accf88 | ||
|
|
353131ab2c | ||
|
|
acb6baa226 | ||
|
|
5b7f7b0860 | ||
|
|
c57238e279 | ||
|
|
24ea4aaed0 | ||
|
|
0af1ae18c8 | ||
|
|
e054df919f | ||
|
|
a9ca557672 | ||
|
|
5bc76dd23d | ||
|
|
f337faeecc | ||
|
|
a6d84c59c9 | ||
|
|
b8279ffe64 | ||
|
|
af44331820 | ||
|
|
00ead34076 | ||
|
|
9b07e167f7 | ||
|
|
0fb15e31d6 | ||
|
|
3e769325f8 | ||
|
|
d555d508c3 | ||
|
|
11511c14bd | ||
|
|
2238ca062f | ||
|
|
3563f18335 | ||
|
|
983ad2faff | ||
|
|
f569da908d | ||
|
|
2e0718ba41 | ||
|
|
846bf82375 | ||
|
|
8cc6f25dd1 | ||
|
|
5ff9ca9815 | ||
|
|
31e6b01b4e | ||
|
|
bc8a6d2db7 | ||
|
|
9a13b33dd8 | ||
|
|
4bdba535bb | ||
|
|
09bf40feee | ||
|
|
5d74d2783f | ||
|
|
807b47dbc4 | ||
|
|
456cdaf883 | ||
|
|
d1b588b7d5 | ||
|
|
22a4b0fcf7 | ||
|
|
84407b5785 | ||
|
|
f5771c56a4 | ||
|
|
a3dee0f70a | ||
|
|
797abcdf87 | ||
|
|
0559c79687 | ||
|
|
f514b86bbc | ||
|
|
49992195df | ||
|
|
631225a108 | ||
|
|
5922951c16 |
65
README.md
65
README.md
@@ -4,7 +4,7 @@
|
||||
</p>
|
||||
<h3 align="center" style="margin:30px 0 30px;font-weight:bold;font-size:30px;">快速开发平台 - Spring Boot</h3>
|
||||
<p align="center">
|
||||
<a href="https://jeesite.com/docs/upgrade/" target="__blank"><img alt="JeeSite-V5.5" src="https://img.shields.io/badge/JeeSite-V5.5-success.svg"></a>
|
||||
<a href="https://jeesite.com/docs/upgrade/" target="__blank"><img alt="JeeSite-V5.7" src="https://img.shields.io/badge/JeeSite-V5.7-success.svg"></a>
|
||||
<a href="https://spring.io/projects/spring-boot#learn" target="__blank"><img alt="SpringBoot-2.7" src="https://img.shields.io/badge/SpringBoot-2.7-blue.svg"></a>
|
||||
<a href="https://gitee.com/thinkgem/jeesite4/stargazers" target="__blank"><img alt="star" src="https://gitee.com/thinkgem/jeesite4/badge/star.svg?theme=dark"></a>
|
||||
<a href="https://gitee.com/thinkgem/jeesite4/members" target="__blank"><img alt="fork" src="https://gitee.com/thinkgem/jeesite4/badge/fork.svg?theme=dark"></a>
|
||||
@@ -28,21 +28,27 @@
|
||||
|
||||
## 平台介绍
|
||||
|
||||
JeeSite 快速开发平台,不仅仅是一个后台开发框架,它是一个企业级快速开发解决方案,后端基于经典组合 Spring Boot、Shiro、MyBatis,前端采用 Beetl、Bootstrap、AdminLTE 经典开发模式,或者分离版 Vue3、Vite、Ant Design Vue、TypeScript、Vben Admin 最先进技术栈。提供在线代码生成功能,可自动创建业务模块工程和微服务模块工程,自动生成前端代码和后端代码;包括功能模块如:组织机构、角色用户、菜单及按钮授权、数据权限、系统参数、内容管理、工作流等。采用松耦合设计,微内核和插件架构,模块增减便捷;界面无刷新,一键换肤;众多账号安全设置,密码策略;文件在线预览;消息推送;多元化第三方登录;在线定时任务配置;支持集群,支持SAAS;支持多数据源;支持读写分离、分库分表;支持微服务应用。
|
||||
JeeSite 快速开发平台,不仅仅是一个后台开发框架,它是一个企业级快速开发解决方案,后端基于经典组合 Spring Boot、Shiro、MyBatis,前端采用 Beetl、Bootstrap、AdminLTE 经典开发模式,或者分离版 Vue3、Vite、Ant Design Vue、TypeScript、Vben Admin 最先进技术栈。
|
||||
|
||||
JeeSite 快速开发平台的主要目的是能够让初级的研发人员快速的开发出复杂的业务功能,中高级人员有时间做一些更有用的事情。让开发者注重专注业务,其余有平台来封装技术细节,降低技术难度,从而节省人力成本,缩短项目周期,提高软件安全质量。
|
||||
提供在线代码生成功能,可自动创建业务模块工程和微服务模块工程,自动生成前端代码和后端代码;包括功能模块如:组织机构、角色用户、菜单及按钮授权、数据权限、系统参数、内容管理、工作流等。
|
||||
|
||||
JeeSite 自 2013 年发布以来已被广大爱好者用到了企业、政府、医疗、金融、互联网等各个领域中,JeeSite 架构精良、易于扩展、大众思维的设计模式、工匠精神打磨每一个细节,深入开发者的内心,并荣获开源中国《最受欢迎中国开源软件》奖杯,期间也帮助了不少刚毕业的大学生,教师作为入门教材,快速的去实践。
|
||||
采用松耦合设计,微内核和插件架构,模块增减便捷;界面细节到位,一键换肤;众多账号安全设置,密码策略;文件在线预览;消息推送;多元化第三方登录;在线定时任务配置;支持集群,支持SAAS;支持多数据源;支持读写分离、分库分表;支持微服务应用。
|
||||
|
||||
JeeSite4 的升级,作者结合了多年总结和经验,以及各方面的应用案例,对架构完成了一次全部重构,也纳入很多新的思想。不管是从开发者模式、底层架构、逻辑处理还是到用户界面,用户交互体验上都有很大的进步,在不忘学习成本、提高开发效率的情况下,安全方面也做和很多工作,包括:身份认证、密码策略、安全审计、日志收集等众多安全选项供你选择。努力为大中小微企业打造全方位企业级快速开发解决方案。
|
||||
主要目的是能够让初级的研发人员快速的开发出复杂的业务功能,中高级人员有时间做一些更有用的事情。让开发者注重专注业务,其余有平台来封装技术细节,降低技术难度,从而节省人力成本,缩短项目周期,提高软件安全质量。
|
||||
|
||||
JeeSite 自 2013 年发布以来已被广大爱好者用到了企业、政府、医疗、金融、互联网等各个领域中,拥有:精良架构、易于扩展、大众思维的设计模式,工匠精神,用心打磨每一个细节,深入开发者的内心,并荣获开源中国《最受欢迎中国开源软件》多次奖项,期间也帮助了不少刚毕业的大学生,教师作为入门教材,快速的去实践。
|
||||
|
||||
2019 年换代升级,作者结合了多年总结和经验,以及各方面的应用案例,对架构完成了一次全部重构,也纳入很多新的思想。不管是从开发者模式、底层架构、逻辑处理还是到用户界面,用户交互体验上都有很大的进步,在不忘学习成本、提高开发效率的情况下,安全方面也做和很多工作,包括:身份认证、密码策略、安全审计、日志收集等众多安全选项供您选择。努力为大中小微企业打造全方位企业级快速开发解决方案。
|
||||
|
||||
2021 年终发布 Vue3 的前后分离版本,使得 JeeSite 拥有同一个后台服务 Web 来支撑分离版和全栈版两套前端技术栈。
|
||||
|
||||
## 平台优势
|
||||
|
||||
JeeSite 整体架构清晰、稳定技术先进、源代码书写规范、经典技术会的人多、易于维护、易于扩展、安全稳定。
|
||||
JeeSite 非常易于二次开发,可控性高,整体架构清晰、技术稳定而先进、源代码书写规范、经典技术会的人多、易于维护、易于扩展、安全稳定。
|
||||
|
||||
JeeSite 功能全,知识点非常多,也非常少。因为她使用的都是一些通用的技术,通俗的设计风格,大多数基础知识点多数人都能掌握,所以每一个 JeeSite 的功能点都非常容易掌握。只要你学会使用这些功能和组件的应用,就可以顺利的完成系统开发了。
|
||||
JeeSite 功能全,知识点非常多,也非常少。因为她使用的都是一些通用的技术,通俗的设计风格,大多数基础知识点,多数人都能掌握,所以每一个 JeeSite 的功能点都非常容易掌握。只要您学会使用这些功能和组件的应用,就可以顺利的完成系统开发了。
|
||||
|
||||
JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,封装不是限制你去做一些事情,而是在便捷的同时,也具有较好的扩展性,在不具备一些功能的情况下,JeeSite 提供了扩展接口,提供了原生调用方法。
|
||||
JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,封装不是限制您去做一些事情,而是在便捷的同时,也具有较好的扩展性,在不具备一些功能的情况下,JeeSite 提供了扩展接口,提供了原生调用方法。
|
||||
|
||||
大家都在用 Spring,也在学习 Spring 的优点,Spring 提供了较好的扩展性,可又有多少人去修改它的源代码呢,退一步说,大家去修改了 Spring 的源码,反而会对未来升级造成很大困扰,您说不是呢?这样的例子很多,所以不要纠结,我们非常注重这一点,JeeSite 也一样具备强大的扩展性。
|
||||
|
||||
@@ -51,12 +57,13 @@ JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,
|
||||
* 至今 JeeSite 平台架构已经非常稳定。
|
||||
* JeeSite 精益求精,用心打磨每一个细节。
|
||||
* JeeSite 是一个专业的平台,是一个让你使用放心的平台。
|
||||
* 社区版基于 Apache License 2.0 开源协议,永久免费使用。
|
||||
|
||||
### 架构特点及安全方面的优势:<https://jeesite.com/docs/feature/>
|
||||
|
||||
## 技术选型
|
||||
|
||||
* 主框架:Spring Boot 2.7、Spring Framework 5.3、Apache Shiro 1.11、J2Cache
|
||||
* 主框架:Spring Boot 2.7、Spring Framework 5.3、Apache Shiro 1.12、J2Cache
|
||||
* 持久层:Apache MyBatis 3.5、Hibernate Validator 6.2、Alibaba Druid 1.2
|
||||
* 视图层:Spring MVC 5.3、Beetl 3.10(替换JSP)、Bootstrap 3.3、AdminLTE 2.4
|
||||
* 前端组件:jQuery 3.7、jqGrid 4.7、layer 3.5、zTree 3.5、jQuery Validation
|
||||
@@ -66,7 +73,7 @@ JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,
|
||||
* Vue3 版 支持现代浏览器,如:谷歌 Chrome 86+、火狐、国产浏览器 等
|
||||
* 技术选型(详细):<http://jeesite.com/docs/technology/>
|
||||
* JeeSite Vue 版本:<https://gitee.com/thinkgem/jeesite-vue>
|
||||
* Spring Boot 3.x 版本:https://gitee.com/thinkgem/jeesite4/tree/v5.springboot3/
|
||||
* Spring Boot 3.x 版本:<https://gitee.com/thinkgem/jeesite4/tree/v5.springboot3>
|
||||
|
||||
## 更多介绍
|
||||
|
||||
@@ -78,50 +85,56 @@ JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,
|
||||
|
||||
## 生态系统
|
||||
|
||||
* 分布式微服务(Spring Cloud):<https://gitee.com/thinkgem/jeesite4-cloud>
|
||||
* 分布式微服务(Spring Cloud):<https://gitee.com/thinkgem/jeesite-cloud>
|
||||
* Flowable业务流程引擎(BPM):<http://jeesite.com/docs/bpm/>
|
||||
* JFlow工作流引擎:<https://gitee.com/thinkgem/jeesite4-jflow> :<http://ccflow.org>
|
||||
* 内容管理模块(CMS):<https://gitee.com/thinkgem/jeesite4/tree/v5.3/modules/cms>
|
||||
* 手机端移动端:<https://gitee.com/thinkgem/jeesite4-uniapp>
|
||||
* JFlow工作流引擎:<https://gitee.com/thinkgem/jeesite-jflow>
|
||||
* 多站点内容管理模块(CMS):<https://jeesite.com/docs/cms/>
|
||||
* 手机端移动端:<https://gitee.com/thinkgem/jeesite-uniapp>
|
||||
* PC客户端程序:<https://gitee.com/thinkgem/jeesite-client>
|
||||
* Vue3分离版本:<https://gitee.com/thinkgem/jeesite-vue>
|
||||
* JeeSite统一认证:<https://jeesite.com/docs/oauth2-server>
|
||||
* MybatisPlus: <https://gitee.com/thinkgem/jeesite-mybatisplus>
|
||||
* Magic接口快速开发:<https://gitee.com/thinkgem/jeesite-magic-api>
|
||||
* 内外网中间件:<https://my.oschina.net/thinkgem/blog/4624519>
|
||||
|
||||
## 快速体验
|
||||
|
||||
### 在线演示
|
||||
|
||||
1. 地址:<http://demo.jeesite.com/>
|
||||
1. 全栈版地址:<http://vue.jeesite.com/js>
|
||||
2. Vue3分离版地址:<http://vue.jeesite.com>
|
||||
|
||||
### 本地运行
|
||||
|
||||
1. 环境准备:`JDK 1.8 or 11、17`、`Maven 3.6+`、使用 `MySQL 5.7 or 8.0` 数据库、[其它数据库](https://jeesite.com/docs/technology/#_8、已支持数据库)
|
||||
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/repository/archive/v5.3.zip> 并解压
|
||||
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/repository/archive/v5.7.zip> 并解压
|
||||
3. 打开文件:`/web/src/main/resources/config/application.yml` 配置JDBC连接
|
||||
4. 执行脚本:`/web/bin/init-data.bat` 初始化数据库
|
||||
5. 执行脚本:`/web/bin/run-tomcat.bat` 启动服务即可
|
||||
6. 浏览器访问:<http://127.0.0.1:8980/js/> 账号 system 密码 admin
|
||||
6. 浏览器访问:<http://127.0.0.1:8980/js> 账号 system 密码 admin
|
||||
7. 部署常见问题:<https://jeesite.com/docs/faq/>
|
||||
8. 分离端安装:<https://jeesite.com/docs/vue-install-deploy/>
|
||||
|
||||
### 快速运行
|
||||
|
||||
1. 环境准备:`JDK 1.8 or 11、17`、`Maven 3.6+`、无需准备数据库(使用内嵌 H2 DB)
|
||||
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/repository/archive/v5.3.zip> 并解压
|
||||
1. 环境准备:`JDK 1.8 or 11、17`、`Maven 3.6+`、无需准备数据库(使用内嵌 H2 DB、Vue资源包)
|
||||
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/repository/archive/v5.7.zip> 并解压
|
||||
3. 执行脚本:`/web-fast/bin/run-tomcat.bat` 启动服务即可(自动初始化库)
|
||||
4. 浏览器访问:<http://127.0.0.1:8980/js/> 账号 system 密码 admin
|
||||
5. 部署常见问题:<https://jeesite.com/docs/faq/>
|
||||
8. 分离端安装:<https://jeesite.com/docs/vue-install-deploy/>
|
||||
4. 全栈版本地址:<http://127.0.0.1:8980/a/login>
|
||||
5. Vue分离版本地址:<http://127.0.0.1:8980/vue/login>
|
||||
6. 默认超级管理员账号:system 密码 admin
|
||||
7. 部署常见问题:<https://jeesite.com/docs/faq/>
|
||||
|
||||
### 容器运行
|
||||
|
||||
- 拉取 Docker 镜像(演示使用,JeeSite版本较久):
|
||||
```
|
||||
```sh
|
||||
docker pull thinkgem/jeesite-web
|
||||
```
|
||||
- 启动脚本:
|
||||
```
|
||||
docker run -d -p 8980:8980 --name jeesite-web -v /data:/data \
|
||||
thinkgem/jeesite-web && docker logs -f jeesite-web
|
||||
```sh
|
||||
docker run --name jeesite-web -p 8980:8980 -d --restart unless-stopped \
|
||||
-v ~/:/data thinkgem/jeesite-web && docker logs -f jeesite-web
|
||||
```
|
||||
- 浏览器访问:<http://127.0.0.1:8980/js/> 账号 system 密码 admin
|
||||
- 分离端安装:<https://jeesite.com/docs/vue-install-deploy/>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.jeesite</groupId>
|
||||
<artifactId>jeesite-parent</artifactId>
|
||||
<version>5.5.0-SNAPSHOT</version>
|
||||
<version>5.7.0-SNAPSHOT</version>
|
||||
<relativePath>../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -391,6 +391,18 @@ public class ListUtils {
|
||||
pageNo++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表分页方法
|
||||
* @param list 源数据
|
||||
* @param pageNo 当前页码
|
||||
* @param pageSize 每页显示条数
|
||||
* @author ThinkGem
|
||||
*/
|
||||
public static <T> List<T> getPageList(List<T> list, int pageNo, int pageSize) {
|
||||
int totalPage = (list.size() + pageSize - 1) / pageSize;
|
||||
return getPageList(list, pageNo, pageSize, totalPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表分页方法
|
||||
|
||||
@@ -779,12 +779,12 @@ public class FileUtils extends org.apache.commons.io.FileUtils {
|
||||
String p = StringUtils.replace(path, WIN_SEPARATOR, SEPARATOR);
|
||||
p = StringUtils.join(StringUtils.split(p, SEPARATOR), SEPARATOR);
|
||||
if (!StringUtils.startsWithAny(p, SEPARATOR) && StringUtils.startsWithAny(path, WIN_SEPARATOR, SEPARATOR)){
|
||||
p += SEPARATOR;
|
||||
p = SEPARATOR + p;
|
||||
}
|
||||
if (!StringUtils.endsWithAny(p, SEPARATOR) && StringUtils.endsWithAny(path, WIN_SEPARATOR, SEPARATOR)){
|
||||
p = p + SEPARATOR;
|
||||
}
|
||||
if (path != null && path.startsWith(SEPARATOR)){
|
||||
if (path != null && path.startsWith(SEPARATOR) && !p.startsWith(SEPARATOR)){
|
||||
p = SEPARATOR + p; // linux下路径
|
||||
}
|
||||
return p;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class PropertyLoader implements org.springframework.boot.env.PropertySour
|
||||
try {
|
||||
// 默认开启 FastJSON 1.x 的,安全模式
|
||||
ParserConfig.getGlobalInstance().setSafeMode(true);
|
||||
} catch (Exception ignored) {
|
||||
} catch (Throwable ignored) {
|
||||
// 兼容 FastJSON 2.x 的调用,忽略异常
|
||||
}
|
||||
Properties properties = PropertiesUtils.getInstance().getProperties();
|
||||
|
||||
@@ -66,9 +66,9 @@ public class ByteUtils {
|
||||
private static String format(double size, String type) {
|
||||
int precision = 0;
|
||||
|
||||
if(size * 1000 % 10 > 0) {
|
||||
/*if(size * 1000 % 10 > 0) {
|
||||
precision = 3;
|
||||
} else if(size * 100 % 10 > 0) {
|
||||
} else */if(size * 100 % 10 > 0) {
|
||||
precision = 2;
|
||||
} else if(size * 10 % 10 > 0) {
|
||||
precision = 1;
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
*/
|
||||
package com.jeesite.common.lang;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 关于异常的工具类.
|
||||
* @author calvin
|
||||
@@ -26,8 +26,8 @@ public class ExceptionUtils {
|
||||
Throwable ex = null;
|
||||
if (request.getAttribute("exception") != null) {
|
||||
ex = (Throwable) request.getAttribute("exception");
|
||||
} else if (request.getAttribute("javax.servlet.error.exception") != null) {
|
||||
ex = (Throwable) request.getAttribute("javax.servlet.error.exception");
|
||||
} else if (request.getAttribute(RequestDispatcher.ERROR_EXCEPTION) != null) {
|
||||
ex = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.Date;
|
||||
public class TimeUtils {
|
||||
|
||||
public static final String[] CN = new String[] {"毫秒", "秒", "分", "时", "天"};
|
||||
public static final String[] EN = new String[] {" millisecond ", " second ", " minute ", " hour ", " day "};
|
||||
public static final String[] EN = new String[] {"ms", " second ", " minute ", " hour ", " day "};
|
||||
|
||||
public static final String[] AGO_CN = new String[] {"刚刚", "秒前", "分钟前", "小时前", "天前"};
|
||||
public static final String[] AGO_EN = new String[] {"just now", " seconds ago", " minutes ago", " hours ago", " days ago"};
|
||||
|
||||
@@ -7,13 +7,16 @@ package com.jeesite.common.mapper;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonParser.Feature;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import com.fasterxml.jackson.databind.introspect.Annotated;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
|
||||
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.util.JSONPObject;
|
||||
import com.jeesite.common.codec.EncodeUtils;
|
||||
import com.jeesite.common.collect.ListUtils;
|
||||
import com.jeesite.common.io.PropertiesUtils;
|
||||
import com.jeesite.common.lang.DateUtils;
|
||||
@@ -31,16 +34,15 @@ import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* 简单封装Jackson,实现JSON String<->Java Object的Mapper.
|
||||
* 封装不同的输出风格, 使用不同的builder函数创建实例.
|
||||
* 封装 Jackson,实现 JSON String 与 Java Object 互转
|
||||
* @author ThinkGem
|
||||
* @version 2016-3-2
|
||||
* @version 2023-09-26
|
||||
*/
|
||||
public class JsonMapper extends ObjectMapper {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(JsonMapper.class);
|
||||
|
||||
/**
|
||||
* 当前类的实例持有者(静态内部类,延迟加载,懒汉式,线程安全的单例模式)
|
||||
@@ -48,7 +50,7 @@ public class JsonMapper extends ObjectMapper {
|
||||
private static final class JsonMapperHolder {
|
||||
private static final JsonMapper INSTANCE = new JsonMapper();
|
||||
}
|
||||
|
||||
|
||||
public JsonMapper() {
|
||||
// Spring ObjectMapper 初始化配置,支持 @JsonView
|
||||
new Jackson2ObjectMapperBuilder().configure(this);
|
||||
@@ -59,9 +61,30 @@ public class JsonMapper extends ObjectMapper {
|
||||
// 允许不带引号的字段名称
|
||||
this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
|
||||
// 设置默认时区
|
||||
this.setDefaultTimeZone();
|
||||
// 设置默认日期格式
|
||||
this.setDefaultDateFormat();
|
||||
// 遇到空值处理为空串
|
||||
this.enabledNullValueToEmpty();
|
||||
// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
|
||||
this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启日期类型默认格式化
|
||||
* @author ThinkGem
|
||||
*/
|
||||
public JsonMapper setDefaultTimeZone(){
|
||||
this.setTimeZone(TimeZone.getTimeZone(PropertiesUtils.getInstance()
|
||||
.getProperty("lang.defaultTimeZone", "GMT+08:00")));
|
||||
// 设置默认日期格式
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启日期类型默认格式化
|
||||
* @author ThinkGem
|
||||
*/
|
||||
public JsonMapper setDefaultDateFormat(){
|
||||
this.setDateFormat(new SimpleDateFormat(PropertiesUtils.getInstance()
|
||||
.getProperty("web.json.defaultDateFormat", "yyyy-MM-dd HH:mm:ss")));
|
||||
this.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
|
||||
@@ -74,8 +97,7 @@ public class JsonMapper extends ObjectMapper {
|
||||
if (jf != null) {
|
||||
return new JsonSerializer<Date>(){
|
||||
@Override
|
||||
public void serialize(Date value, JsonGenerator jgen,
|
||||
SerializerProvider provider) throws IOException, JsonProcessingException {
|
||||
public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||
if (value != null){
|
||||
jgen.writeString(DateUtils.formatDate(value, jf.pattern()));
|
||||
}
|
||||
@@ -86,27 +108,39 @@ public class JsonMapper extends ObjectMapper {
|
||||
return super.findSerializer(a);
|
||||
}
|
||||
});
|
||||
// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
|
||||
this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
// 遇到空值处理为空串
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启将空值转换为空字符串
|
||||
* @author ThinkGem
|
||||
*/
|
||||
public JsonMapper enabledNullValueToEmpty(){
|
||||
this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>(){
|
||||
@Override
|
||||
public void serialize(Object value, JsonGenerator jgen,
|
||||
SerializerProvider provider) throws IOException, JsonProcessingException {
|
||||
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||
jgen.writeString(StringUtils.EMPTY);
|
||||
}
|
||||
});
|
||||
// // 进行HTML解码(先注释掉,否则会造成XSS攻击,比如菜单名称里输入<script>alert(123)</script>转josn后就会还原这个编码 ,并在浏览器中运行)。
|
||||
// this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>(){
|
||||
// @Override
|
||||
// public void serialize(String value, JsonGenerator jgen,
|
||||
// SerializerProvider provider) throws IOException,
|
||||
// JsonProcessingException {
|
||||
// if (value != null){
|
||||
// jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
|
||||
// }
|
||||
// }
|
||||
// }));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启 XSS 过滤器
|
||||
* @author ThinkGem
|
||||
*/
|
||||
public JsonMapper enabledXssFilter(){
|
||||
this.registerModule(new SimpleModule().addDeserializer(String.class, new JsonDeserializer<String>() {
|
||||
@Override
|
||||
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
String text = p.getText();
|
||||
if (text != null) {
|
||||
return EncodeUtils.xssFilter(text);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -93,7 +93,7 @@ public class IpUtils {
|
||||
}
|
||||
|
||||
public static byte[] textToNumericFormatV4(String paramString) {
|
||||
if (paramString.length() == 0) {
|
||||
if (paramString.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
byte[] arrayOfByte = new byte[4];
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.jeesite.common.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
@@ -7,8 +9,6 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 身份证工具类
|
||||
*
|
||||
@@ -152,7 +152,7 @@ public class IdcardUtils extends StringUtils {
|
||||
int iSum17 = getPowerSum(iCard);
|
||||
// 获取校验位
|
||||
String sVal = getCheckCode18(iSum17);
|
||||
if (sVal.length() > 0) {
|
||||
if (!sVal.isEmpty()) {
|
||||
idCard18 += sVal;
|
||||
} else {
|
||||
return null;
|
||||
@@ -205,7 +205,7 @@ public class IdcardUtils extends StringUtils {
|
||||
int iSum17 = getPowerSum(iCard);
|
||||
// 获取校验位
|
||||
String val = getCheckCode18(iSum17);
|
||||
if (val.length() > 0) {
|
||||
if (!val.isEmpty()) {
|
||||
if (val.equalsIgnoreCase(code18)) {
|
||||
bTrue = true;
|
||||
}
|
||||
|
||||
@@ -187,6 +187,8 @@ a, a:hover, a:active, a:focus, .form-unit, th[aria-selected=true] .ui-jqgrid-sor
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#1890ff!important;border-color:#1890ff;}
|
||||
.form-unit, th[aria-selected=true] .ui-jqgrid-sortable {color:#1890ff;}
|
||||
.form-unit {border-bottom:1px solid #eee;}
|
||||
|
||||
@@ -209,6 +209,8 @@ a, a:hover, a:active, a:focus, .form-unit, th[aria-selected=true] .ui-jqgrid-sor
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#1890ff!important;border-color:#1890ff!important;}
|
||||
.form-unit, th[aria-selected=true] .ui-jqgrid-sortable {color:#1890ff;}
|
||||
.form-unit {border-bottom:1px solid #eee;}
|
||||
|
||||
@@ -187,6 +187,8 @@ a, a:hover, a:active, a:focus, .form-unit, th[aria-selected=true] .ui-jqgrid-sor
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#1e5edb!important;border-color:#1e5edb!important;}
|
||||
.form-unit, th[aria-selected=true] .ui-jqgrid-sortable {color:#1e5edb;}
|
||||
.form-unit {border-bottom:1px solid #eee;}
|
||||
|
||||
@@ -209,6 +209,8 @@ a, a:hover, a:active, a:focus, .form-unit, th[aria-selected=true] .ui-jqgrid-sor
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#1e5edb!important;border-color:#1e5edb!important;}
|
||||
.form-unit, th[aria-selected=true] .ui-jqgrid-sortable {color:#1e5edb;}
|
||||
.form-unit {border-bottom:1px solid #eee;}
|
||||
|
||||
@@ -222,7 +222,9 @@ a, a:hover, a:active, a:focus, .form-unit, th[aria-selected=true] .ui-jqgrid-sor
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#1e5edb!important;border-color:#1e5edb!important;}
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#3aa0ff!important;border-color:#3aa0ff!important;}
|
||||
.form-unit, th[aria-selected=true] .ui-jqgrid-sortable {color:#2975bc;}
|
||||
.form-unit {border-bottom:1px solid #4e4e4e;}
|
||||
|
||||
|
||||
@@ -156,4 +156,6 @@ th[aria-selected=true] .ui-jqgrid-sortable {color:#00a65a;}
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#00a65a!important;border-color:#00a65a;}
|
||||
|
||||
@@ -141,4 +141,6 @@ th[aria-selected=true] .ui-jqgrid-sortable {color:#00a65a;}
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#00a65a!important;border-color:#00a65a;}
|
||||
|
||||
@@ -156,4 +156,6 @@ th[aria-selected=true] .ui-jqgrid-sortable {color:#605ca8;}
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#605ca8!important;border-color:#605ca8;}
|
||||
|
||||
@@ -141,4 +141,6 @@ th[aria-selected=true] .ui-jqgrid-sortable {color:#605ca8;}
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#605ca8!important;border-color:#605ca8;}
|
||||
|
||||
@@ -156,4 +156,6 @@ th[aria-selected=true] .ui-jqgrid-sortable {color:#dd4b39;}
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#dd4b39!important;border-color:#dd4b39;}
|
||||
|
||||
@@ -141,4 +141,6 @@ th[aria-selected=true] .ui-jqgrid-sortable {color:#dd4b39;}
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#dd4b39!important;border-color:#dd4b39;}
|
||||
|
||||
@@ -156,4 +156,6 @@ th[aria-selected=true] .ui-jqgrid-sortable {color:#f39c12;}
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#f39c12!important;border-color:#f39c12;}
|
||||
|
||||
@@ -141,4 +141,6 @@ th[aria-selected=true] .ui-jqgrid-sortable {color:#f39c12;}
|
||||
.open>.dropdown-toggle.btn-primary:hover, .layui-layer-btn .layui-layer-btn0,
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice,
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected],
|
||||
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover,
|
||||
.pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover,
|
||||
.wup_container .placeholder .webuploader-pick {background-color:#f39c12!important;border-color:#f39c12;}
|
||||
|
||||
@@ -710,6 +710,7 @@ Class.pt.callback = function(){
|
||||
var that = this, layero = that.layero, config = that.config;
|
||||
that.openLayer();
|
||||
if(config.success){
|
||||
layero.find('.layui-layer-close').focus(); // 弹窗后首先关闭获取焦点,防止回车弹出多个
|
||||
if(config.type == 2){
|
||||
layero.find('iframe').on('load', function(){
|
||||
config.success(layero, that.index);
|
||||
|
||||
@@ -4469,7 +4469,7 @@ S2.define('select2/dropdown/closeOnSelect',[
|
||||
});
|
||||
|
||||
// ThinkGem 默认为中文
|
||||
S2.define('select2/i18n/en',[],function () {
|
||||
S2.define('select2/i18n/zh_CN',[],function () {
|
||||
// English
|
||||
return {
|
||||
errorLoading: function () {
|
||||
@@ -4549,7 +4549,7 @@ S2.define('select2/defaults',[
|
||||
'./dropdown/selectOnClose',
|
||||
'./dropdown/closeOnSelect',
|
||||
|
||||
'./i18n/en'
|
||||
'./i18n/zh_CN'
|
||||
], function ($, require,
|
||||
|
||||
ResultsList,
|
||||
@@ -4763,7 +4763,7 @@ S2.define('select2/defaults',[
|
||||
|
||||
if ($.isArray(options.language)) {
|
||||
var languages = new Translation();
|
||||
options.language.push('en');
|
||||
options.language.push('zh_CN');
|
||||
|
||||
var languageNames = options.language;
|
||||
|
||||
@@ -4800,7 +4800,7 @@ S2.define('select2/defaults',[
|
||||
options.translations = languages;
|
||||
} else {
|
||||
var baseTranslation = Translation.loadPath(
|
||||
this.defaults.amdLanguageBase + 'en'
|
||||
this.defaults.amdLanguageBase + 'zh_CN'
|
||||
);
|
||||
var customTranslation = new Translation(options.language);
|
||||
|
||||
@@ -4952,6 +4952,8 @@ S2.define('select2/options',[
|
||||
this.options.language = $e.prop('lang').toLowerCase();
|
||||
} else if ($e.closest('[lang]').prop('lang')) {
|
||||
this.options.language = $e.closest('[lang]').prop('lang');
|
||||
} else if (window.lang) {
|
||||
this.options.language = window.lang;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
modules/app/db/app.png
Normal file
BIN
modules/app/db/app.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.jeesite</groupId>
|
||||
<artifactId>jeesite-parent</artifactId>
|
||||
<version>5.5.0-SNAPSHOT</version>
|
||||
<version>5.7.0-SNAPSHOT</version>
|
||||
<relativePath>../../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.jeesite.common.callback.MethodCallback;
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.tests.BaseInitDataTests;
|
||||
import com.jeesite.modules.app.entity.AppComment;
|
||||
|
||||
@@ -11,4 +11,9 @@
|
||||
5.3.2
|
||||
5.4.0
|
||||
5.4.1
|
||||
5.5.0
|
||||
5.5.0
|
||||
5.5.1
|
||||
5.5.2
|
||||
5.6.0
|
||||
5.6.1
|
||||
5.7.0
|
||||
@@ -18,20 +18,20 @@
|
||||
data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
|
||||
<div class="form-group">
|
||||
<label class="control-label">${text('问题分类')}:</label>
|
||||
<div class="control-inline width-120">
|
||||
<div class="control-inline width-90">
|
||||
<#form:select path="category" dictType="app_comment_category" blankOption="true" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">${text('问题和意见')}:</label>
|
||||
<div class="control-inline">
|
||||
<#form:input path="content" maxlength="500" class="form-control width-120"/>
|
||||
<#form:input path="content" maxlength="500" class="form-control width-90"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">${text('联系方式')}:</label>
|
||||
<div class="control-inline">
|
||||
<#form:input path="contact" maxlength="200" class="form-control width-120"/>
|
||||
<#form:input path="contact" maxlength="200" class="form-control width-90"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -49,8 +49,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-search"></i> ${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick"><i class="glyphicon glyphicon-repeat"></i> ${text('重置')}</button>
|
||||
</div>
|
||||
</#form:form>
|
||||
<table id="dataGrid"></table>
|
||||
@@ -62,7 +62,7 @@
|
||||
<script>
|
||||
//# // 初始化DataGrid对象
|
||||
$('#dataGrid').dataGrid({
|
||||
searchForm: $("#searchForm"),
|
||||
searchForm: $('#searchForm'),
|
||||
columnModel: [
|
||||
{header:'${text("问题和意见")}', name:'content', index:'a.content', width:250, align:"left", frozen:true, formatter: function(val, obj, row, act){
|
||||
return '<a href="${ctx}/app/appComment/form?id='+row.id+'" class="btnList" data-title="${text("编辑意见")}">'+(val||row.id)+'</a>';
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
|
||||
<div class="form-group">
|
||||
<label class="control-label">${text('应用代号')}:</label>
|
||||
<div class="control-inline width-120">
|
||||
<div class="control-inline width-90">
|
||||
<#form:select path="appCode" dictType="app_code" blankOption="true" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">${text('升级标题')}:</label>
|
||||
<div class="control-inline">
|
||||
<#form:input path="upTitle" maxlength="200" class="form-control width-120"/>
|
||||
<#form:input path="upTitle" maxlength="200" class="form-control width-90"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">${text('升级类型')}:</label>
|
||||
<div class="control-inline width-120">
|
||||
<div class="control-inline width-90">
|
||||
<#form:select path="upType" dictType="app_upgrade_type" blankOption="true" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,8 +48,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-search"></i> ${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick"><i class="glyphicon glyphicon-repeat"></i> ${text('重置')}</button>
|
||||
</div>
|
||||
</#form:form>
|
||||
<table id="dataGrid"></table>
|
||||
@@ -61,7 +61,7 @@
|
||||
<script>
|
||||
//# // 初始化DataGrid对象
|
||||
$('#dataGrid').dataGrid({
|
||||
searchForm: $("#searchForm"),
|
||||
searchForm: $('#searchForm'),
|
||||
columnModel: [
|
||||
{header:'${text("升级标题")}', name:'upTitle', index:'a.up_title', width:350, align:"left", frozen:true, formatter: function(val, obj, row, act){
|
||||
return '<a href="${ctx}/app/appUpgrade/form?id='+row.id+'" class="btnList" data-title="${text("编辑版本")}">'+(val||row.id)+'</a>';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
modules/cms/db/cms.png
Normal file
BIN
modules/cms/db/cms.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.jeesite</groupId>
|
||||
<artifactId>jeesite-parent</artifactId>
|
||||
<version>5.5.0-SNAPSHOT</version>
|
||||
<version>5.7.0-SNAPSHOT</version>
|
||||
<relativePath>../../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
Binary file not shown.
@@ -18,18 +18,7 @@ j2cache:
|
||||
cmsPageCache: 100000, 7d
|
||||
|
||||
#spring:
|
||||
# data:
|
||||
# elasticsearch:
|
||||
# # 开启 ES 功能
|
||||
# enabled: true
|
||||
#
|
||||
# # 设置 ES 服务地址
|
||||
# client:
|
||||
# reactive:
|
||||
# endpoints: 127.0.0.1:9200
|
||||
#
|
||||
# # 连接超时的时间
|
||||
# properties:
|
||||
# transport:
|
||||
# tcp:
|
||||
# connect_timeout: 120s
|
||||
# elasticsearch:
|
||||
# enabled: true
|
||||
# uris: http://Win11:9200
|
||||
# connection-timeout: 120s
|
||||
|
||||
@@ -19,4 +19,9 @@
|
||||
5.3.2
|
||||
5.4.0
|
||||
5.4.1
|
||||
5.5.0
|
||||
5.5.0
|
||||
5.5.1
|
||||
5.5.2
|
||||
5.6.0
|
||||
5.6.1
|
||||
5.7.0
|
||||
@@ -2,8 +2,8 @@
|
||||
// Bootswatch
|
||||
// -----------------------------------------------------
|
||||
|
||||
$web-font-path: "https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700" !default;
|
||||
@import url($web-font-path);
|
||||
//$web-font-path: "https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700" !default;
|
||||
//@import url($web-font-path);
|
||||
|
||||
// Navbar =====================================================================
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700");
|
||||
/*@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700");*/
|
||||
/*!
|
||||
* bootswatch v3.4.1
|
||||
* Homepage: http://bootswatch.com
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700");/*!
|
||||
/*@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700");*/
|
||||
/*!
|
||||
* bootswatch v3.4.1
|
||||
* Homepage: http://bootswatch.com
|
||||
* Copyright 2012-2019 Thomas Park
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// Bootswatch
|
||||
// -----------------------------------------------------
|
||||
|
||||
@web-font-path: "https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700";
|
||||
|
||||
.web-font(@path) {
|
||||
@import (css) url("@{path}");
|
||||
}
|
||||
.web-font(@web-font-path);
|
||||
//@web-font-path: "https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700";
|
||||
//
|
||||
//.web-font(@path) {
|
||||
// @import (css) url("@{path}");
|
||||
//}
|
||||
//.web-font(@web-font-path);
|
||||
|
||||
// Navbar =====================================================================
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<label class="control-label col-sm-4" title="">
|
||||
<span class="required ">*</span> ${text('所属栏目')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:treeselect id="category" title="${text('所属栏目')}"
|
||||
<#form:treeselect id="category" title="${text('所属栏目')}"
|
||||
path="category.categoryCode" labelPath="category.categoryName"
|
||||
url="${ctx}/cms/category/treeData?excludeCode=${article.category.categoryCode}"
|
||||
class="required" allowClear="false" canSelectRoot="true" canSelectParent="false" />
|
||||
@@ -70,145 +70,145 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="${text('数值越大排序越靠前,可设置权重过期时间')}。">
|
||||
${text('权重/排序')}: <i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<div class="form-inline m0">
|
||||
<#form:input path="weight" class="form-control width-90 digits" maxlength="10"/>
|
||||
<#form:checkbox id="weightTop" label="${text('置顶')}" value="${article.weight==9999 ?'1' : ''}"
|
||||
class="form-control" style="vertical-align:middle;"/>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="${text('数值越大排序越靠前,可设置权重过期时间')}。">
|
||||
${text('权重/排序')}: <i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<div class="form-inline m0">
|
||||
<#form:input path="weight" class="form-control width-90 digits" maxlength="10"/>
|
||||
<#form:checkbox id="weightTop" label="${text('置顶')}" value="${article.weight==9999 ?'1' : ''}"
|
||||
class="form-control" style="vertical-align:middle;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="${text('时间到期后,权重自动恢复为0,如果为空,则权重永不过期')}。">
|
||||
${text('权重过期时间')}: <i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:input path="weightDate" readonly="true" maxlength="20" class="form-control laydate"
|
||||
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="${text('时间到期后,权重自动恢复为0,如果为空,则权重永不过期')}。">
|
||||
${text('权重过期时间')}: <i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:input path="weightDate" readonly="true" maxlength="20" class="form-control laydate"
|
||||
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-unit">${text('详细信息')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-1">${text('摘要')}:</label>
|
||||
<div class="col-sm-11">
|
||||
<#form:textarea path="description" maxlength="500" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-1">${text('正文')}:</label>
|
||||
<div class="col-sm-11">
|
||||
<#form:ueditor id="content" path="articleData.content" maxlength="10000" height="500" class="required" outline="${parameter.outline}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-unit">${text('其他信息')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="">
|
||||
<span class="required hide">*</span> ${text('内容图片')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:fileupload id="uploadImage" bizKey="${article.id}"
|
||||
bizType="article_image" returnPath="true"
|
||||
filePathInputId="image" uploadType="image" readonly="false"
|
||||
maxUploadNum="4" isMini="false" />
|
||||
<#form:input path="image" maxlength="1000" readonly="true" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="">
|
||||
<span class="required hide">*</span> ${text('关键字')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:input path="keywords" maxlength="500" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4">${text('推荐位')}:</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="checkbox-list">
|
||||
<#form:checkbox path="posidList" dictType="cms_post" class="form-control" />
|
||||
<div class="form-unit">${text('详细信息')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-1">${text('摘要')}:</label>
|
||||
<div class="col-sm-11">
|
||||
<#form:textarea path="description" maxlength="500" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="${text('文章的发布状态')}">${text('状态')}:<i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:select path="state" dictType="sys_status" blankOption="true" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="${text('可修改发布时间,不填则使用当前时间')}">
|
||||
${text('发布时间')}: <i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:input path="createDate" readonly="true" maxlength="20" class="form-control laydate"
|
||||
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-1">${text('正文')}:</label>
|
||||
<div class="col-sm-11">
|
||||
<#form:ueditor id="content" path="articleData.content" maxlength="10000" height="500" class="required" outline="${parameter.outline}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-unit">${text('高级信息')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="">
|
||||
<span class="required hide">*</span> ${text('自定义内容视图')}:<i class="fa icon-question" title="自定义内容视图名称必须以'${article_DEFAULT_TEMPLATE}'开始"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:select path="customContentView" items="${contentViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
|
||||
<div class="form-unit">${text('其他信息')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="">
|
||||
<span class="required hide">*</span> ${text('内容图片')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:fileupload id="uploadImage" bizKey="${article.id}"
|
||||
bizType="article_image" returnPath="true"
|
||||
filePathInputId="image" uploadType="image" readonly="false"
|
||||
maxUploadNum="4" isMini="false" />
|
||||
<#form:input path="image" maxlength="1000" readonly="true" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="">
|
||||
<span class="required hide">*</span> ${text('视图参数配置')}:<i class="fa icon-question" title="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:input path="viewConfig" maxlength="1000" placeholder="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:${'${'}viewConfig_count}、${'${'}viewConfig_titleShow}" class="form-control"/>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="">
|
||||
<span class="required hide">*</span> ${text('关键字')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:input path="keywords" maxlength="500" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4">${text('推荐位')}:</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="checkbox-list">
|
||||
<#form:checkbox path="posidList" dictType="cms_post" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="">
|
||||
<span class="required hide">*</span> ${text('备注信息')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:textarea path="remarks" rows="4" maxlength="500" class="form-control"/>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="${text('文章的发布状态')}">${text('状态')}:<i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:select path="state" dictType="sys_status" blankOption="true" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="${text('可修改发布时间,不填则使用当前时间')}">
|
||||
${text('发布时间')}: <i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:input path="createDate" readonly="true" maxlength="20" class="form-control laydate"
|
||||
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-unit">${text('页面配置')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="">
|
||||
<span class="required hide">*</span> ${text('自定义内容视图')}:<i class="fa icon-question" title="自定义内容视图名称必须以'${article_DEFAULT_TEMPLATE}'开始"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:select path="customContentView" items="${contentViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="">
|
||||
<span class="required hide">*</span> ${text('视图参数配置')}:<i class="fa icon-question" title="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:input path="viewConfig" maxlength="1000" placeholder="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:${'${'}viewConfig_count}、${'${'}viewConfig_titleShow}" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="">
|
||||
<span class="required hide">*</span> ${text('备注信息')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:textarea path="remarks" rows="4" maxlength="500" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<#form:extend collapsed="true" pathPrefix="articleData"/>
|
||||
</div>
|
||||
<#form:extend collapsed="true" pathPrefix="articleData"/>
|
||||
<div class="box-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
@@ -226,7 +226,7 @@
|
||||
<script src="${ctxStatic}/colorpicker/bootstrap-colorpicker.js"></script>
|
||||
<script type="text/javascript">
|
||||
// 颜色控件初始化
|
||||
$("#inputForm .input-color").colorpicker();
|
||||
$('#inputForm .input-color').colorpicker();
|
||||
// 权重、排序
|
||||
$('#weightTop input').on('ifChecked ifUnchecked', function(){
|
||||
if ($(this).is(':checked')){
|
||||
@@ -235,7 +235,7 @@ $('#weightTop input').on('ifChecked ifUnchecked', function(){
|
||||
$('#weight').val('0');
|
||||
}
|
||||
});
|
||||
$("#inputForm").validate({
|
||||
$('#inputForm').validate({
|
||||
submitHandler: function(form){
|
||||
$('#wordCount').val(contentUE.getContentTxt().length);
|
||||
js.ajaxSubmitForm($(form), function(data){
|
||||
|
||||
@@ -28,12 +28,12 @@
|
||||
<#form:input path="title" maxlength="255" class="form-control width-120"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<!--<div class="form-group">
|
||||
<label class="control-label">${text('关键字')}:</label>
|
||||
<div class="control-inline">
|
||||
<#form:input path="keywords" maxlength="500" class="form-control width-120"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="form-group">
|
||||
<label class="control-label">${text('状态')}:</label>
|
||||
<div class="control-inline width-90">
|
||||
@@ -41,8 +41,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-search"></i> ${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick"><i class="glyphicon glyphicon-repeat"></i> ${text('重置')}</button>
|
||||
</div>
|
||||
</#form:form>
|
||||
<table id="dataGrid"></table>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</div>
|
||||
<#form:form id="inputForm" model="${category}" action="${ctx}/cms/category/save" method="post" class="form-horizontal">
|
||||
<div class="box-body">
|
||||
<div class="form-unit">${text('基本信息')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
@@ -131,112 +132,112 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-unit">${text('栏目配置')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="是否在导航中显示该栏目">
|
||||
<span class="required hide">*</span> ${text('是否在导航中显示')}:<i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="inMenu" dictType="sys_show_hide" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="">
|
||||
<span class="required hide">*</span> ${text('是否允许评论')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="isCanComment" dictType="sys_yes_no" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="是否在分类页中显示该栏目的文章列表">
|
||||
<span class="required hide">*</span> ${text('是否在分类页中显示')}:<i class="fa icon-question" ></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="inList" dictType="sys_show_hide" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title=""> <span class="required hide">*</span>
|
||||
${text('是否需要审核')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="isNeedAudit" dictType="sys_yes_no" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="默认展现方式,首栏目内容列表,栏目第一条内容">
|
||||
<span class="required hide">*</span> ${text('内容展现模式')}:<i class="fa icon-question" ></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="showModes" dictType="cms_show_modes" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="自定义内容视图名称必须以'${category_DEFAULT_TEMPLATE}'开始">
|
||||
${text('自定义列表视图')}:<i class="fa icon-question "></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:select path="customListView" items="${listViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="自定义内容视图名称必须以'${article_DEFAULT_TEMPLATE}'开始"> <span class="required hide">*</span>
|
||||
${text('自定义内容视图')}:<i class="fa icon-question "></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:select path="customContentView" items="${contentViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}">
|
||||
${text('视图参数配置')}:<i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:input path="viewConfig" maxlength="1000" class="form-control"
|
||||
placeholder="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:${'${'}viewConfig_count}、${'${'}viewConfig_titleShow}" />
|
||||
<br />
|
||||
<ul class="text-muted well well-lg no-shadow m0 pt10 pb10">
|
||||
<li>例如视图参数设置为:{count:2,titleShow:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}。</li>
|
||||
<li>设置栏目的管理地址:若设置【adminUrl:false】表示无管理地址,在内容发布栏目列表中不显示该栏目;</li>
|
||||
<li>设置【adminUrl:'/cms/guestbook'】表示有管理地址,在内容发布栏目列表中点击该栏目链接到该地址。</li>
|
||||
<!-- <li>管理地址参数:若设置【adminUrlParam:'fileDownload=true'】则代表链接模型为文件下载的栏目,新增链接的时候出现文件上传对话框。</li>
|
||||
<li>管理地址参数:若设置【adminUrlParam:'outlineView=true'】则代表文章模型开启大纲视图编辑,在线编辑器左侧显示大纲视图。</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-unit">${text('其他信息')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="">
|
||||
<span class="required hide">*</span> ${text('备注信息')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:textarea path="remarks" rows="4" maxlength="500" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<#form:extend collapsed="true" />
|
||||
</div>
|
||||
<div class="form-unit">${text('栏目配置')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="是否在导航中显示该栏目">
|
||||
<span class="required hide">*</span> ${text('是否在导航中显示')}:<i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="inMenu" dictType="sys_show_hide" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="">
|
||||
<span class="required hide">*</span> ${text('是否允许评论')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="isCanComment" dictType="sys_yes_no" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="是否在分类页中显示该栏目的文章列表">
|
||||
<span class="required hide">*</span> ${text('是否在分类页中显示')}:<i class="fa icon-question" ></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="inList" dictType="sys_show_hide" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title=""> <span class="required hide">*</span>
|
||||
${text('是否需要审核')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="isNeedAudit" dictType="sys_yes_no" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="默认展现方式,首栏目内容列表,栏目第一条内容">
|
||||
<span class="required hide">*</span> ${text('内容展现模式')}:<i class="fa icon-question" ></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:radio path="showModes" dictType="cms_show_modes" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="自定义内容视图名称必须以'${category_DEFAULT_TEMPLATE}'开始">
|
||||
${text('自定义列表视图')}:<i class="fa icon-question "></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:select path="customListView" items="${listViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-4" title="自定义内容视图名称必须以'${article_DEFAULT_TEMPLATE}'开始"> <span class="required hide">*</span>
|
||||
${text('自定义内容视图')}:<i class="fa icon-question "></i></label>
|
||||
<div class="col-sm-8">
|
||||
<#form:select path="customContentView" items="${contentViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}">
|
||||
${text('视图参数配置')}:<i class="fa icon-question"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:input path="viewConfig" maxlength="1000" class="form-control"
|
||||
placeholder="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:${'${'}viewConfig_count}、${'${'}viewConfig_titleShow}" />
|
||||
<br />
|
||||
<ul class="text-muted well well-lg no-shadow m0 pt10 pb10">
|
||||
<li>例如视图参数设置为:{count:2,titleShow:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}。</li>
|
||||
<li>设置栏目的管理地址:若设置【adminUrl:false】表示无管理地址,在内容发布栏目列表中不显示该栏目;</li>
|
||||
<li>设置【adminUrl:'/cms/guestbook'】表示有管理地址,在内容发布栏目列表中点击该栏目链接到该地址。</li>
|
||||
<!-- <li>管理地址参数:若设置【adminUrlParam:'fileDownload=true'】则代表链接模型为文件下载的栏目,新增链接的时候出现文件上传对话框。</li>
|
||||
<li>管理地址参数:若设置【adminUrlParam:'outlineView=true'】则代表文章模型开启大纲视图编辑,在线编辑器左侧显示大纲视图。</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-unit">${text('其他信息')}</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" title="">
|
||||
<span class="required hide">*</span> ${text('备注信息')}:<i class="fa icon-question hide"></i></label>
|
||||
<div class="col-sm-10">
|
||||
<#form:textarea path="remarks" rows="4" maxlength="500" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<#form:extend collapsed="true" />
|
||||
<div class="box-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
@@ -252,7 +253,7 @@
|
||||
</div>
|
||||
<% } %>
|
||||
<script>
|
||||
$("#inputForm").validate({
|
||||
$('#inputForm').validate({
|
||||
submitHandler : function(form) {
|
||||
js.ajaxSubmitForm($(form), function(data) {
|
||||
js.showMessage(data.message);
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-search"></i> ${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick"><i class="glyphicon glyphicon-repeat"></i> ${text('重置')}</button>
|
||||
</div>
|
||||
</#form:form>
|
||||
<table id="dataGrid"></table>
|
||||
|
||||
@@ -94,8 +94,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-search"></i> ${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick"><i class="glyphicon glyphicon-repeat"></i> ${text('重置')}</button>
|
||||
</div>
|
||||
</#form:form>
|
||||
<table id="dataGrid"></table>
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-search"></i> ${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick"><i class="glyphicon glyphicon-repeat"></i> ${text('重置')}</button>
|
||||
</div>
|
||||
</#form:form>
|
||||
<table id="dataGrid"></table>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<% layout('/layouts/default.html', {title: '站点管理', libs: ['validate','fileupload','ueditor','dataGrid']}){ %>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="box box-main">
|
||||
<div class="box-header with-border">
|
||||
@@ -71,12 +70,10 @@
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">${text('站点logo')}</label>
|
||||
<div class="col-sm-10">
|
||||
<#form:fileupload id="uploadLogo" bizKey="${site.id}" bizType="site_logo" returnPath="true"
|
||||
filePathInputId="logo"
|
||||
uploadType="image" readonly="false" maxUploadNum="1" isMini="false"/>
|
||||
<#form:input path="logo" class="form-control"/>
|
||||
|
||||
|
||||
<#form:fileupload id="uploadLogo" bizKey="${site.id}" bizType="site_logo" returnPath="true"
|
||||
filePathInputId="logo" uploadType="image" readonly="false" maxUploadNum="1" isMini="false"/>
|
||||
<#form:input path="logo" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -163,7 +160,7 @@
|
||||
</div>
|
||||
<% } %>
|
||||
<script>
|
||||
$("#inputForm").validate({
|
||||
$('#inputForm').validate({
|
||||
submitHandler: function(form){
|
||||
js.ajaxSubmitForm($(form), function(data){
|
||||
js.showMessage(data.message);
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-search"></i> ${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick"><i class="glyphicon glyphicon-repeat"></i> ${text('重置')}</button>
|
||||
</div>
|
||||
</#form:form>
|
||||
<table id="dataGrid"></table>
|
||||
|
||||
@@ -53,8 +53,8 @@
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-search"></i> ${text('查询')}</button>
|
||||
<button type="reset" class="btn btn-default btn-sm isQuick"><i class="glyphicon glyphicon-repeat"></i> ${text('重置')}</button>
|
||||
</div>
|
||||
</#form:form>
|
||||
<table id="dataGrid"></table>
|
||||
|
||||
10406
modules/core/db/core.erm
10406
modules/core/db/core.erm
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 1007 KiB After Width: | Height: | Size: 3.3 MiB |
BIN
modules/core/db/core.xlsx
Normal file
BIN
modules/core/db/core.xlsx
Normal file
Binary file not shown.
@@ -476,6 +476,8 @@ CREATE TABLE js_sys_module
|
||||
main_class_name varchar(500),
|
||||
current_version varchar(50),
|
||||
upgrade_info varchar(300),
|
||||
gen_base_dir vargraphic(1000),
|
||||
tpl_category varchar(200),
|
||||
status char(1) DEFAULT '0' NOT NULL,
|
||||
create_by varchar(64) NOT NULL,
|
||||
create_date timestamp NOT NULL,
|
||||
|
||||
@@ -476,6 +476,8 @@ CREATE TABLE js_sys_module
|
||||
main_class_name varchar(500),
|
||||
current_version varchar(50),
|
||||
upgrade_info varchar(300),
|
||||
gen_base_dir varchar(1000),
|
||||
tpl_category varchar(200),
|
||||
status char(1) DEFAULT '0' NOT NULL,
|
||||
create_by varchar(64) NOT NULL,
|
||||
create_date datetime NOT NULL,
|
||||
|
||||
4534
modules/core/db/job.erm
Normal file
4534
modules/core/db/job.erm
Normal file
File diff suppressed because it is too large
Load Diff
BIN
modules/core/db/job.png
Normal file
BIN
modules/core/db/job.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 531 KiB |
BIN
modules/core/db/job.xlsx
Normal file
BIN
modules/core/db/job.xlsx
Normal file
Binary file not shown.
@@ -476,6 +476,8 @@ CREATE TABLE [js_sys_module]
|
||||
[main_class_name] varchar(500),
|
||||
[current_version] varchar(50),
|
||||
[upgrade_info] varchar(300),
|
||||
[gen_base_dir] nvarchar(1000),
|
||||
[tpl_category] varchar(200),
|
||||
[status] char(1) DEFAULT '0' NOT NULL,
|
||||
[create_by] varchar(64) NOT NULL,
|
||||
[create_date] datetime NOT NULL,
|
||||
|
||||
@@ -477,6 +477,8 @@ CREATE TABLE js_sys_module
|
||||
main_class_name varchar(500) COMMENT '主类全名',
|
||||
current_version varchar(50) COMMENT '当前版本',
|
||||
upgrade_info varchar(300) COMMENT '升级信息',
|
||||
gen_base_dir varchar(1000) COMMENT '生成基础路径',
|
||||
tpl_category varchar(200) COMMENT '使用的模板',
|
||||
status char(1) DEFAULT '0' NOT NULL COMMENT '状态(0正常 1删除 2停用)',
|
||||
create_by varchar(64) NOT NULL COMMENT '创建者',
|
||||
create_date datetime NOT NULL COMMENT '创建时间',
|
||||
|
||||
@@ -476,6 +476,8 @@ CREATE TABLE js_sys_module
|
||||
main_class_name varchar2(500),
|
||||
current_version varchar2(50),
|
||||
upgrade_info varchar2(300),
|
||||
gen_base_dir nvarchar2(1000),
|
||||
tpl_category varchar2(200),
|
||||
status char(1) DEFAULT '0' NOT NULL,
|
||||
create_by varchar2(64) NOT NULL,
|
||||
create_date timestamp NOT NULL,
|
||||
@@ -1336,6 +1338,8 @@ COMMENT ON COLUMN js_sys_module.description IS '模块描述';
|
||||
COMMENT ON COLUMN js_sys_module.main_class_name IS '主类全名';
|
||||
COMMENT ON COLUMN js_sys_module.current_version IS '当前版本';
|
||||
COMMENT ON COLUMN js_sys_module.upgrade_info IS '升级信息';
|
||||
COMMENT ON COLUMN js_sys_module.gen_base_dir IS '生成基础路径';
|
||||
COMMENT ON COLUMN js_sys_module.tpl_category IS '使用的模板';
|
||||
COMMENT ON COLUMN js_sys_module.status IS '状态(0正常 1删除 2停用)';
|
||||
COMMENT ON COLUMN js_sys_module.create_by IS '创建者';
|
||||
COMMENT ON COLUMN js_sys_module.create_date IS '创建时间';
|
||||
|
||||
@@ -476,6 +476,8 @@ CREATE TABLE js_sys_module
|
||||
main_class_name varchar(500),
|
||||
current_version varchar(50),
|
||||
upgrade_info varchar(300),
|
||||
gen_base_dir varchar(1000),
|
||||
tpl_category varchar(200),
|
||||
status char(1) DEFAULT '0' NOT NULL,
|
||||
create_by varchar(64) NOT NULL,
|
||||
create_date timestamp NOT NULL,
|
||||
@@ -1336,6 +1338,8 @@ COMMENT ON COLUMN js_sys_module.description IS '模块描述';
|
||||
COMMENT ON COLUMN js_sys_module.main_class_name IS '主类全名';
|
||||
COMMENT ON COLUMN js_sys_module.current_version IS '当前版本';
|
||||
COMMENT ON COLUMN js_sys_module.upgrade_info IS '升级信息';
|
||||
COMMENT ON COLUMN js_sys_module.gen_base_dir IS '生成基础路径';
|
||||
COMMENT ON COLUMN js_sys_module.tpl_category IS '使用的模板';
|
||||
COMMENT ON COLUMN js_sys_module.status IS '状态(0正常 1删除 2停用)';
|
||||
COMMENT ON COLUMN js_sys_module.create_by IS '创建者';
|
||||
COMMENT ON COLUMN js_sys_module.create_date IS '创建时间';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.jeesite</groupId>
|
||||
<artifactId>jeesite-parent</artifactId>
|
||||
<version>5.5.0-SNAPSHOT</version>
|
||||
<version>5.7.0-SNAPSHOT</version>
|
||||
<relativePath>../../parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Oracle 11g -->
|
||||
<dependency>
|
||||
<groupId>com.oracle</groupId>
|
||||
@@ -36,37 +37,33 @@
|
||||
<version>11.2.0.3</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- Oracle 12c
|
||||
<!-- Oracle 12c 及以上版本
|
||||
<dependency>
|
||||
<groupId>com.oracle.ojdbc</groupId>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc8</artifactId>
|
||||
<version>19.3.0.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.ojdbc</groupId>
|
||||
<artifactId>orai18n</artifactId>
|
||||
<version>19.3.0.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency> -->
|
||||
<!-- SqlServer 2008 -->
|
||||
|
||||
<!-- SqlServer 2008
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.jtds</groupId>
|
||||
<artifactId>jtds</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- SqlServer 2012
|
||||
</dependency> -->
|
||||
<!-- SqlServer 2012 及以上版本 -->
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency> -->
|
||||
</dependency>
|
||||
|
||||
<!-- PostgreSQL -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- H2 DB
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
@@ -87,6 +84,11 @@
|
||||
<artifactId>jeesite-framework</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
<!--<artifactId>spring-boot-starter-undertow</artifactId>-->
|
||||
</dependency>
|
||||
|
||||
<!-- ELK 日志收集 -->
|
||||
<dependency>
|
||||
|
||||
@@ -2,13 +2,20 @@
|
||||
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
*/
|
||||
package com.jeesite.modules.config;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
package com.jeesite.autoconfigure.core;
|
||||
|
||||
import com.jeesite.common.collect.ListUtils;
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.shiro.cas.CasOutHandler;
|
||||
import com.jeesite.common.shiro.config.FilterChainDefinitionMap;
|
||||
import com.jeesite.common.shiro.filter.*;
|
||||
import com.jeesite.common.shiro.realm.AuthorizingRealm;
|
||||
import com.jeesite.common.shiro.realm.CasAuthorizingRealm;
|
||||
import com.jeesite.common.shiro.realm.LdapAuthorizingRealm;
|
||||
import com.jeesite.common.shiro.session.SessionDAO;
|
||||
import com.jeesite.common.shiro.session.SessionManager;
|
||||
import com.jeesite.common.shiro.web.ShiroFilterFactoryBean;
|
||||
import com.jeesite.common.shiro.web.WebSecurityManager;
|
||||
import org.apache.shiro.cache.CacheManager;
|
||||
import org.apache.shiro.cas.CasSubjectFactory;
|
||||
import org.apache.shiro.realm.Realm;
|
||||
@@ -17,49 +24,33 @@ import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
||||
import org.apache.shiro.web.filter.InvalidRequestFilter;
|
||||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import com.jeesite.common.collect.ListUtils;
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.shiro.cas.CasOutHandler;
|
||||
import com.jeesite.common.shiro.config.FilterChainDefinitionMap;
|
||||
import com.jeesite.common.shiro.filter.CasFilter;
|
||||
import com.jeesite.common.shiro.filter.FormFilter;
|
||||
import com.jeesite.common.shiro.filter.InnerFilter;
|
||||
import com.jeesite.common.shiro.filter.LdapFilter;
|
||||
import com.jeesite.common.shiro.filter.LogoutFilter;
|
||||
import com.jeesite.common.shiro.filter.PermissionsFilter;
|
||||
import com.jeesite.common.shiro.filter.RolesFilter;
|
||||
import com.jeesite.common.shiro.filter.UserFilter;
|
||||
import com.jeesite.common.shiro.realm.AuthorizingRealm;
|
||||
import com.jeesite.common.shiro.realm.CasAuthorizingRealm;
|
||||
import com.jeesite.common.shiro.realm.LdapAuthorizingRealm;
|
||||
import com.jeesite.common.shiro.session.SessionDAO;
|
||||
import com.jeesite.common.shiro.session.SessionManager;
|
||||
import com.jeesite.common.shiro.web.ShiroFilterFactoryBean;
|
||||
import com.jeesite.common.shiro.web.WebSecurityManager;
|
||||
import javax.servlet.Filter;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Shiro配置
|
||||
* @author ThinkGem
|
||||
* @version 2021-7-6
|
||||
* @version 2023-12-20
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AutoConfiguration(before = SessionAutoConfiguration.class)
|
||||
@ConditionalOnProperty(name="user.enabled", havingValue="true", matchIfMissing=true)
|
||||
public class ShiroConfig {
|
||||
|
||||
public class ShiroAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Apache Shiro Filter
|
||||
*/
|
||||
@Bean
|
||||
@Bean("shiroFilterProxy")
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 5000)
|
||||
@ConditionalOnMissingBean(name="shiroFilterProxy")
|
||||
public FilterRegistrationBean<Filter> shiroFilterProxy(ShiroFilterFactoryBean shiroFilter) throws Exception {
|
||||
@@ -69,14 +60,14 @@ public class ShiroConfig {
|
||||
bean.setOrder(Ordered.HIGHEST_PRECEDENCE + 5000);
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 内部系统访问过滤器
|
||||
*/
|
||||
private InnerFilter shiroInnerFilter() {
|
||||
return new InnerFilter();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CAS登录过滤器
|
||||
*/
|
||||
@@ -85,7 +76,7 @@ public class ShiroConfig {
|
||||
bean.setAuthorizingRealm(casAuthorizingRealm);
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* LDAP登录过滤器
|
||||
*/
|
||||
@@ -133,7 +124,7 @@ public class ShiroConfig {
|
||||
private UserFilter shiroUserFilter() {
|
||||
return new UserFilter();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 非法请求过滤器
|
||||
*/
|
||||
@@ -142,12 +133,13 @@ public class ShiroConfig {
|
||||
bean.setBlockNonAscii(false);
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shiro认证过滤器
|
||||
*/
|
||||
@Bean
|
||||
public ShiroFilterFactoryBean shiroFilter(WebSecurityManager webSecurityManager, AuthorizingRealm authorizingRealm,
|
||||
@Bean("shiroFilter")
|
||||
@ConditionalOnMissingBean(name="shiroFilter")
|
||||
public ShiroFilterFactoryBean shiroFilter(WebSecurityManager webSecurityManager, AuthorizingRealm authorizingRealm,
|
||||
CasAuthorizingRealm casAuthorizingRealm, LdapAuthorizingRealm ldapAuthorizingRealm) {
|
||||
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
|
||||
bean.setSecurityManager(webSecurityManager);
|
||||
@@ -169,30 +161,33 @@ public class ShiroConfig {
|
||||
bean.setFilterChainDefinitionMap(chains.getObject());
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 系统安全认证实现类
|
||||
*/
|
||||
@Bean
|
||||
public AuthorizingRealm authorizingRealm(SessionDAO sessionDAO) {
|
||||
@Bean("authorizingRealm")
|
||||
@ConditionalOnMissingBean(name="authorizingRealm")
|
||||
public AuthorizingRealm authorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO) {
|
||||
AuthorizingRealm bean = new AuthorizingRealm();
|
||||
bean.setSessionDAO(sessionDAO);
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 单点登录信息句柄,单点退出用
|
||||
*/
|
||||
@Bean
|
||||
@Bean("casOutHandler")
|
||||
@ConditionalOnMissingBean(name="casOutHandler")
|
||||
public CasOutHandler casOutHandler() {
|
||||
return new CasOutHandler();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CAS安全认证实现类
|
||||
*/
|
||||
@Bean
|
||||
public CasAuthorizingRealm casAuthorizingRealm(SessionDAO sessionDAO, CasOutHandler casOutHandler) {
|
||||
@Bean("casAuthorizingRealm")
|
||||
@ConditionalOnMissingBean(name="casAuthorizingRealm")
|
||||
public CasAuthorizingRealm casAuthorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO, CasOutHandler casOutHandler) {
|
||||
CasAuthorizingRealm bean = new CasAuthorizingRealm();
|
||||
bean.setSessionDAO(sessionDAO);
|
||||
bean.setCasOutHandler(casOutHandler);
|
||||
@@ -200,12 +195,13 @@ public class ShiroConfig {
|
||||
bean.setCasServerCallbackUrl(Global.getProperty("shiro.casClientUrl") + Global.getAdminPath() + "/login-cas");
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* LDAP安全认证实现类
|
||||
*/
|
||||
@Bean
|
||||
public LdapAuthorizingRealm ldapAuthorizingRealm(SessionDAO sessionDAO, CasOutHandler casOutHandler) {
|
||||
@Bean("ldapAuthorizingRealm")
|
||||
@ConditionalOnMissingBean(name="ldapAuthorizingRealm")
|
||||
public LdapAuthorizingRealm ldapAuthorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO, CasOutHandler casOutHandler) {
|
||||
LdapAuthorizingRealm bean = new LdapAuthorizingRealm();
|
||||
JndiLdapContextFactory contextFactory = (JndiLdapContextFactory) bean.getContextFactory();
|
||||
contextFactory.setUrl(Global.getProperty("shiro.ldapUrl"/*, "ldap://127.0.0.1:389"*/));
|
||||
@@ -217,9 +213,10 @@ public class ShiroConfig {
|
||||
/**
|
||||
* 定义Shiro安全管理配置
|
||||
*/
|
||||
@Bean
|
||||
@Bean("webSecurityManager")
|
||||
@ConditionalOnMissingBean(name="webSecurityManager")
|
||||
public WebSecurityManager webSecurityManager(AuthorizingRealm authorizingRealm, CasAuthorizingRealm casAuthorizingRealm,
|
||||
LdapAuthorizingRealm ldapAuthorizingRealm, SessionManager sessionManager, CacheManager shiroCacheManager) {
|
||||
LdapAuthorizingRealm ldapAuthorizingRealm, SessionManager sessionManager, @Qualifier("shiroCacheManager") CacheManager shiroCacheManager) {
|
||||
WebSecurityManager bean = new WebSecurityManager();
|
||||
Collection<Realm> realms = ListUtils.newArrayList();
|
||||
realms.add(authorizingRealm); // 第一个为权限授权控制类
|
||||
@@ -232,21 +229,23 @@ public class ShiroConfig {
|
||||
//bean.setRememberMeManager(null); // 关闭 RememberMe
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shiro 生命周期处理器,实现初始化和销毁回调
|
||||
*/
|
||||
@Bean(name="lifecycleBeanPostProcessor")
|
||||
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
|
||||
@Bean("lifecycleBeanPostProcessor")
|
||||
@ConditionalOnMissingBean(name="lifecycleBeanPostProcessor")
|
||||
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
|
||||
return new LifecycleBeanPostProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shiro 过滤器代理配置
|
||||
*/
|
||||
@Bean
|
||||
@Bean("defaultAdvisorAutoProxyCreator")
|
||||
@DependsOn({ "lifecycleBeanPostProcessor" })
|
||||
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
|
||||
@ConditionalOnMissingBean(name="defaultAdvisorAutoProxyCreator")
|
||||
public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
|
||||
DefaultAdvisorAutoProxyCreator bean = new DefaultAdvisorAutoProxyCreator();
|
||||
bean.setProxyTargetClass(true);
|
||||
return bean;
|
||||
@@ -255,22 +254,11 @@ public class ShiroConfig {
|
||||
/**
|
||||
* 启用Shrio授权注解拦截方式,AOP式方法级权限检查
|
||||
*/
|
||||
@Bean
|
||||
@Bean("authorizationAttributeSourceAdvisor")
|
||||
@ConditionalOnMissingBean(name="authorizationAttributeSourceAdvisor")
|
||||
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(WebSecurityManager webSecurityManager) {
|
||||
AuthorizationAttributeSourceAdvisor bean = new AuthorizationAttributeSourceAdvisor();
|
||||
bean.setSecurityManager(webSecurityManager);
|
||||
return bean;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 在方法中 注入 webSecurityManager 进行代理控制
|
||||
// */
|
||||
// @Bean
|
||||
// public MethodInvokingFactoryBean methodInvokingFactoryBean(DefaultWebSecurityManager webSecurityManager) {
|
||||
// MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();
|
||||
// bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
|
||||
// bean.setArguments(new Object[] { webSecurityManager });
|
||||
// return bean;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import com.jeesite.common.lang.StringUtils;
|
||||
import com.jeesite.common.network.IpUtils;
|
||||
import com.jeesite.common.shiro.authc.FormToken;
|
||||
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
|
||||
import com.jeesite.common.utils.SpringUtils;
|
||||
import com.jeesite.common.web.CookieUtils;
|
||||
import com.jeesite.common.web.http.ServletUtils;
|
||||
import com.jeesite.modules.sys.entity.Log;
|
||||
@@ -31,7 +32,6 @@ import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.apache.shiro.session.Session;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.servlet.Cookie;
|
||||
import org.apache.shiro.web.servlet.Cookie.SameSiteOptions;
|
||||
import org.apache.shiro.web.servlet.SimpleCookie;
|
||||
import org.apache.shiro.web.util.WebUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -60,23 +60,21 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
|
||||
public static final String LOGIN_PARAM = "__login"; // 支持GET方式登录的参数
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FormFilter.class);
|
||||
|
||||
private static FormFilter instance;
|
||||
private static Cookie sessionIdCookie;
|
||||
private static Cookie rememberUserCodeCookie;
|
||||
|
||||
private BaseAuthorizingRealm authorizingRealm;
|
||||
private Cookie rememberUserCodeCookie; // 记住用户名Cookie
|
||||
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public FormFilter() {
|
||||
super();
|
||||
rememberUserCodeCookie = new SimpleCookie();
|
||||
sessionIdCookie = SpringUtils.getBean("sessionIdCookie");
|
||||
rememberUserCodeCookie = new SimpleCookie(sessionIdCookie);
|
||||
rememberUserCodeCookie.setName(REMEMBER_USERCODE_PARAM);
|
||||
rememberUserCodeCookie.setPath(Global.getProperty("session.sessionIdCookiePath"));
|
||||
rememberUserCodeCookie.setSecure(Global.getPropertyToBoolean("session.sessionIdCookieSecure", "false"));
|
||||
rememberUserCodeCookie.setHttpOnly(Global.getPropertyToBoolean("session.sessionIdCookieHttpOnly", "true"));
|
||||
String sameSite = Global.getProperty("session.sessionIdCookieSameSite", "Lax"); // Null、None、Lax、Strict
|
||||
rememberUserCodeCookie.setSameSite(!"Null".equalsIgnoreCase(sameSite) ? SameSiteOptions.valueOf(StringUtils.upperCase(sameSite)) : null);
|
||||
rememberUserCodeCookie.setMaxAge(Cookie.ONE_YEAR);
|
||||
instance = this;
|
||||
}
|
||||
@@ -200,14 +198,6 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
|
||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||
return (!isLoginRequest(request, response) && isPermissive(mappedValue)); // 不验证登录状态,只验证登录请求
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转登录页时,跳转到默认首页
|
||||
*/
|
||||
@Override
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
|
||||
PermissionsFilter.redirectToDefaultPath(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 地址访问接入验证
|
||||
@@ -255,6 +245,14 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
|
||||
boolean isLogin = WebUtils.isTrue(request, LOGIN_PARAM);
|
||||
return super.isLoginSubmission(request, response) || isLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转登录页时,跳转到默认首页
|
||||
*/
|
||||
@Override
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
|
||||
PermissionsFilter.redirectToDefaultPath(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行登录方法
|
||||
@@ -361,20 +359,9 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
|
||||
// 是否显示验证码
|
||||
data.put("isValidCodeLogin", Global.getConfigToInteger("sys.login.failedNumAfterValidCode", "200") == 0);
|
||||
|
||||
//获取当前会话对象
|
||||
Session session = UserUtils.getSession();
|
||||
data.put("sessionid", (String)session.getId());
|
||||
|
||||
// 如果登录设置了语言,则切换语言
|
||||
if (paramMap.get("lang") != null){
|
||||
Global.setLang((String)paramMap.get("lang"), request, response);
|
||||
}
|
||||
|
||||
// 设置公共结果数据
|
||||
setCommonData(request, response, data, paramMap);
|
||||
data.put("result", "login");
|
||||
data.put("demoMode", Global.isDemoMode());
|
||||
data.put("useCorpModel", Global.isUseCorpModel()
|
||||
&& Global.getConfigToBoolean("user.loginCodeCorpUnique", "false"));
|
||||
data.put("title", Global.getProperty("productName"));
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -415,30 +402,47 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
|
||||
String corpCode = (String)paramMap.get("corpCode");
|
||||
User user = UserUtils.getByLoginCode(username, corpCode);
|
||||
LogUtils.saveLog(user, request, "登录失败", Log.TYPE_LOGIN_LOGOUT);
|
||||
|
||||
//获取当前会话对象
|
||||
Session session = UserUtils.getSession();
|
||||
data.put("sessionid", (String)session.getId());
|
||||
|
||||
// 如果登录设置了语言,则切换语言
|
||||
|
||||
// 设置公共结果数据
|
||||
setCommonData(request, response, data, paramMap);
|
||||
data.put("result", Global.FALSE);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置公共数据
|
||||
* @author ThinkGem
|
||||
*/
|
||||
private static void setCommonData(HttpServletRequest request, HttpServletResponse response,
|
||||
Map<String, Object> data, Map<String, Object> paramMap) {
|
||||
if (ServletUtils.isAjaxRequest(request)) {
|
||||
Session session = UserUtils.getSession();
|
||||
data.put("sessionid", session.getId());
|
||||
Cookie cookie = new SimpleCookie(sessionIdCookie);
|
||||
cookie.setValue((String)session.getId());
|
||||
cookie.saveTo(request, response);
|
||||
}
|
||||
if (paramMap.get("lang") != null){
|
||||
Global.setLang((String)paramMap.get("lang"), request, response);
|
||||
}
|
||||
|
||||
data.put("result", Global.FALSE);
|
||||
data.put("demoMode", Global.isDemoMode());
|
||||
data.put("useCorpModel", Global.isUseCorpModel()
|
||||
&& Global.getConfigToBoolean("user.loginCodeCorpUnique", "false"));
|
||||
data.put("title", Global.getProperty("productName"));
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录页面数据
|
||||
* @author ThinkGem
|
||||
*/
|
||||
public static Map<String, Object> getLoginSuccessData(User user, Session session) {
|
||||
public static Map<String, Object> getLoginSuccessData(HttpServletRequest request, HttpServletResponse response,
|
||||
User user, Session session) {
|
||||
Map<String, Object> data = MapUtils.newHashMap();
|
||||
if (ServletUtils.isAjaxRequest(request)) {
|
||||
Cookie cookie = new SimpleCookie(sessionIdCookie);
|
||||
cookie.setValue((String)session.getId());
|
||||
cookie.saveTo(request, response);
|
||||
}
|
||||
data.put("user", user); // 设置当前用户信息
|
||||
data.put("demoMode", Global.isDemoMode());
|
||||
data.put("useCorpModel", Global.isUseCorpModel());
|
||||
|
||||
@@ -19,15 +19,17 @@ import javax.servlet.http.HttpServletRequest;
|
||||
*/
|
||||
public class InnerFilter extends AccessControlFilter {
|
||||
|
||||
private static final String[] prefixes = Global.getPropertyToArray("shiro.innerFilterAllowRemoteAddrs", "127.0.0.1");
|
||||
|
||||
@Override
|
||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
|
||||
boolean result = false;
|
||||
String[] prefixes = (String[])mappedValue;
|
||||
if (prefixes == null){
|
||||
prefixes = Global.getPropertyToArray("shiro.innerFilterAllowRemoteAddrs", "127.0.0.1");
|
||||
prefixes = InnerFilter.prefixes;
|
||||
}
|
||||
if (prefixes != null && request instanceof HttpServletRequest){
|
||||
String ip = request.getRemoteAddr();
|
||||
String ip = request.getRemoteAddr() + "]";
|
||||
for (String prefix : prefixes){
|
||||
result = StringUtils.startsWithIgnoreCase(ip, StringUtils.trim(prefix));
|
||||
if (result){
|
||||
|
||||
@@ -29,11 +29,6 @@ import com.jeesite.common.web.http.wrapper.GetHttpServletRequestWrapper;
|
||||
*/
|
||||
public class PermissionsFilter extends org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter {
|
||||
|
||||
@Override
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
|
||||
PermissionsFilter.redirectToDefaultPath(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
|
||||
return PermissionsFilter.redirectTo403Page(request, response);
|
||||
@@ -99,5 +94,10 @@ public class PermissionsFilter extends org.apache.shiro.web.filter.authz.Permiss
|
||||
WebUtils.issueRedirect(request, response, loginUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
|
||||
PermissionsFilter.redirectToDefaultPath(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
*/
|
||||
package com.jeesite.common.shiro.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 角色权限过滤器
|
||||
@@ -16,14 +15,14 @@ import javax.servlet.ServletResponse;
|
||||
*/
|
||||
public class RolesFilter extends org.apache.shiro.web.filter.authz.RolesAuthorizationFilter {
|
||||
|
||||
@Override
|
||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
|
||||
return PermissionsFilter.redirectTo403Page(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
|
||||
PermissionsFilter.redirectToDefaultPath(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
|
||||
return PermissionsFilter.redirectTo403Page(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
*/
|
||||
package com.jeesite.common.shiro.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.lang.StringUtils;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 用户权限过滤器
|
||||
@@ -16,14 +19,36 @@ import javax.servlet.ServletResponse;
|
||||
*/
|
||||
public class UserFilter extends org.apache.shiro.web.filter.authc.UserFilter {
|
||||
|
||||
@Override
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
|
||||
PermissionsFilter.redirectToDefaultPath(request, response);
|
||||
private String sessionIdHeaderName;
|
||||
|
||||
public UserFilter () {
|
||||
this.setSessionIdHeaderName(Global.getProperty("session.sessionIdHeaderName", "x-token"));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||
String sessionId = (String)request.getAttribute(getSessionIdHeaderName());
|
||||
if (StringUtils.isNotBlank(sessionId)) {
|
||||
((HttpServletResponse)response).setHeader(getSessionIdHeaderName(), sessionId);
|
||||
}
|
||||
return super.isAccessAllowed(request, response, mappedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
|
||||
return PermissionsFilter.redirectTo403Page(request, response);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
|
||||
PermissionsFilter.redirectToDefaultPath(request, response);
|
||||
}
|
||||
|
||||
public String getSessionIdHeaderName() {
|
||||
return sessionIdHeaderName;
|
||||
}
|
||||
|
||||
public void setSessionIdHeaderName(String sessionIdHeaderName) {
|
||||
this.sessionIdHeaderName = sessionIdHeaderName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ import com.jeesite.modules.sys.utils.UserUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.AuthenticationInfo;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.authz.AuthorizationInfo;
|
||||
import org.apache.shiro.session.Session;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -25,13 +28,13 @@ import javax.servlet.http.HttpServletRequest;
|
||||
* @version 2018-7-11
|
||||
*/
|
||||
public class AuthorizingRealm extends BaseAuthorizingRealm {
|
||||
|
||||
|
||||
public static final String HASH_ALGORITHM = "SHA-1";
|
||||
public static final int HASH_INTERATIONS = 1024;
|
||||
public static final int SALT_SIZE = 8;
|
||||
|
||||
|
||||
private UserService userService;
|
||||
|
||||
|
||||
public AuthorizingRealm() {
|
||||
super();
|
||||
// // 设定密码校验的Hash算法与迭代次数(V4.1.4及以上版本不需要了,统一使用validatePassword验证密码)
|
||||
@@ -39,7 +42,7 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
|
||||
// matcher.setHashIterations(HASH_INTERATIONS);
|
||||
// this.setCredentialsMatcher(matcher);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取登录凭证,将 authcToken 转换为 FormToken,参考 CAS 实现
|
||||
*/
|
||||
@@ -47,7 +50,7 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
|
||||
protected FormToken getFormToken(AuthenticationToken authcToken) {
|
||||
return super.getFormToken(authcToken);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于用户根据登录信息获取用户信息<br>
|
||||
* 1、默认根据登录账号登录信息,如:UserUtils.getByLoginCode(formToken.getUsername(), formToken.getParam("corpCode"));<br>
|
||||
@@ -58,7 +61,7 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
|
||||
protected User getUserInfo(FormToken formToken) {
|
||||
return super.getUserInfo(formToken);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验登录凭证,如密码验证,token验证,验证失败抛出 AuthenticationException 异常
|
||||
*/
|
||||
@@ -66,6 +69,14 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
|
||||
protected void assertCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo authcInfo) throws AuthenticationException {
|
||||
super.assertCredentialsMatch(authcToken, authcInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户授权信息,默认返回类型 SimpleAuthorizationInfo
|
||||
*/
|
||||
@Override
|
||||
protected AuthorizationInfo doGetAuthorizationInfo(LoginInfo loginInfo, Subject subject, Session session, User user) {
|
||||
return super.doGetAuthorizationInfo(loginInfo, subject, session, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成密文密码,生成随机的16位salt并经过1024次 sha-1 hash
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
package com.jeesite.common.ueditor.upload;
|
||||
|
||||
import com.jeesite.common.image.ImageUtils;
|
||||
import com.jeesite.common.io.FileUtils;
|
||||
import com.jeesite.common.media.VideoUtils;
|
||||
import com.jeesite.common.ueditor.PathFormat;
|
||||
import com.jeesite.common.ueditor.define.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -8,21 +17,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
|
||||
import com.jeesite.common.image.ImageUtils;
|
||||
import com.jeesite.common.io.FileUtils;
|
||||
import com.jeesite.common.media.VideoUtils;
|
||||
import com.jeesite.common.ueditor.PathFormat;
|
||||
import com.jeesite.common.ueditor.define.ActionMap;
|
||||
import com.jeesite.common.ueditor.define.AppInfo;
|
||||
import com.jeesite.common.ueditor.define.BaseState;
|
||||
import com.jeesite.common.ueditor.define.FileType;
|
||||
import com.jeesite.common.ueditor.define.State;
|
||||
|
||||
public class BinaryUploader {
|
||||
|
||||
public static final State save(HttpServletRequest request, Map<String, Object> conf) {
|
||||
@@ -64,7 +58,7 @@ public class BinaryUploader {
|
||||
|
||||
savePath = PathFormat.parse(savePath, originFileName);
|
||||
|
||||
String physicalPath = FileUtils.path((String) conf.get("rootPath") + savePath);
|
||||
String physicalPath = FileUtils.path(conf.get("rootPath") + savePath);
|
||||
|
||||
InputStream is = null;
|
||||
State storageState = null;
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
package com.jeesite.common.ueditor.upload;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.idgen.IdGen;
|
||||
import com.jeesite.common.io.FileUtils;
|
||||
import com.jeesite.common.io.PropertiesUtils;
|
||||
@@ -14,6 +8,11 @@ import com.jeesite.common.lang.StringUtils;
|
||||
import com.jeesite.common.ueditor.define.AppInfo;
|
||||
import com.jeesite.common.ueditor.define.BaseState;
|
||||
import com.jeesite.common.ueditor.define.State;
|
||||
import com.jeesite.common.web.http.ServletUtils;
|
||||
import com.jeesite.modules.file.utils.FileUploadUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.*;
|
||||
|
||||
public class StorageManager {
|
||||
|
||||
@@ -194,12 +193,21 @@ public class StorageManager {
|
||||
|
||||
/**
|
||||
* UEditor上传文件成功后调用事件
|
||||
*
|
||||
* @param physicalPath 上传文件实际路径
|
||||
* @param storageState url 返回到客户端的文件访问地址
|
||||
*/
|
||||
public static void uploadFileSuccess(String physicalPath, State storageState) {
|
||||
|
||||
if (!Global.getPropertyToBoolean("file.enabled", "true")) {
|
||||
return;
|
||||
}
|
||||
File file = new File(physicalPath);
|
||||
String url = FileUploadUtils.ossFileUpload(file, StringUtils.substringAfter(
|
||||
FileUtils.path(file.getAbsolutePath()), Global.USERFILES_BASE_URL));
|
||||
if (!StringUtils.contains(url, "://")) {
|
||||
HttpServletRequest request = ServletUtils.getRequest();
|
||||
url = FileUtils.path((request != null ? request.getContextPath() : StringUtils.EMPTY) + url);
|
||||
}
|
||||
storageState.putInfo("url", url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
|
||||
* No deletion without permission, or be held responsible to law.
|
||||
*/
|
||||
package com.jeesite.modules.config.web;
|
||||
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.lang.StringUtils;
|
||||
import com.jeesite.common.web.http.ServletUtils;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* IP地址黑白名单过滤器配置
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class IpAddrFilterConfig {
|
||||
|
||||
private static long clearCacheTime;
|
||||
private static String[] allowPrefixes;
|
||||
private static String[] denyPrefixes;
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<Filter> ipAddrFilter() {
|
||||
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
|
||||
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
bean.setFilter((setvletRequest, setvletResponse, chain) -> {
|
||||
if (isAccessAllowed(setvletRequest, setvletResponse)) {
|
||||
chain.doFilter(setvletRequest, setvletResponse);
|
||||
} else {
|
||||
HttpServletResponse response = (HttpServletResponse) setvletResponse;
|
||||
response.setStatus(403);
|
||||
ServletUtils.renderString(response, Global.getText("访问拒绝"));
|
||||
}
|
||||
});
|
||||
bean.addUrlPatterns("/*");
|
||||
return bean;
|
||||
}
|
||||
|
||||
private boolean isAccessAllowed(ServletRequest request, ServletResponse response) {
|
||||
if (clearCacheTime == 0 || clearCacheTime != Global.getClearCacheTime()) {
|
||||
allowPrefixes = Global.getConfigToArray("sys.filter.allowIpAddrs", StringUtils.EMPTY);
|
||||
denyPrefixes = Global.getConfigToArray("sys.filter.denyIpAddrs", StringUtils.EMPTY);
|
||||
clearCacheTime = Global.getClearCacheTime();
|
||||
}
|
||||
// 如果未初始化,直接拒绝
|
||||
if (allowPrefixes == null || denyPrefixes == null) {
|
||||
return false;
|
||||
}
|
||||
// 如果未设置黑白名单,直接通过
|
||||
if (allowPrefixes.length == 0 && denyPrefixes.length == 0) {
|
||||
return true;
|
||||
}
|
||||
// 如果未设置白名单,则直接通过白名单,再从黑名单中检查
|
||||
boolean result = allowPrefixes.length == 0;
|
||||
String ip = request.getRemoteAddr() + "]";
|
||||
for (String prefix : allowPrefixes) {
|
||||
if (StringUtils.startsWithIgnoreCase(ip, StringUtils.trim(prefix))){
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (String prefix : denyPrefixes) {
|
||||
if (StringUtils.startsWithIgnoreCase(ip, StringUtils.trim(prefix))){
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -4,23 +4,16 @@
|
||||
*/
|
||||
package com.jeesite.modules.config.web;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
/**
|
||||
* 将请求协议转换为 https
|
||||
* @author ThinkGem
|
||||
@@ -34,35 +27,23 @@ public class SchemeHttpsConfig {
|
||||
public FilterRegistrationBean<Filter> schemeFilterRegistrationBean() {
|
||||
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
|
||||
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
bean.setFilter(new Filter() {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
bean.setFilter((request, response, chain) -> {
|
||||
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return "https";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return "https";
|
||||
@Override
|
||||
public StringBuffer getRequestURL() {
|
||||
StringBuffer sb = super.getRequestURL();
|
||||
if ("http:".equals(sb.substring(0, 5))){
|
||||
return sb.replace(0, 5, "https:");
|
||||
}else{
|
||||
return sb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuffer getRequestURL() {
|
||||
StringBuffer sb = super.getRequestURL();
|
||||
if ("http:".equals(sb.substring(0, 5))){
|
||||
return sb.replace(0, 5, "https:");
|
||||
}else{
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
|
||||
}, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {}
|
||||
}
|
||||
}, response);
|
||||
});
|
||||
bean.addUrlPatterns("/*");
|
||||
return bean;
|
||||
|
||||
@@ -4,9 +4,14 @@
|
||||
*/
|
||||
package com.jeesite.modules.msg.web;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.entity.Page;
|
||||
import com.jeesite.common.lang.StringUtils;
|
||||
import com.jeesite.common.web.BaseController;
|
||||
import com.jeesite.modules.msg.entity.MsgInner;
|
||||
import com.jeesite.modules.msg.entity.MsgInnerRecord;
|
||||
import com.jeesite.modules.msg.entity.MsgPush;
|
||||
import com.jeesite.modules.msg.service.MsgInnerService;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -18,14 +23,8 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.jeesite.common.config.Global;
|
||||
import com.jeesite.common.entity.Page;
|
||||
import com.jeesite.common.lang.StringUtils;
|
||||
import com.jeesite.common.web.BaseController;
|
||||
import com.jeesite.modules.msg.entity.MsgInner;
|
||||
import com.jeesite.modules.msg.entity.MsgInnerRecord;
|
||||
import com.jeesite.modules.msg.entity.MsgPush;
|
||||
import com.jeesite.modules.msg.service.MsgInnerService;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 内部消息Controller
|
||||
@@ -122,7 +121,8 @@ public class MsgInnerController extends BaseController {
|
||||
return renderResult(Global.FALSE, "数据已发布,不允许修改!");
|
||||
}
|
||||
msgInnerService.save(msgInner);
|
||||
return renderResult(Global.TRUE, text("保存消息成功!"));
|
||||
return renderResult(Global.TRUE, text((MsgInner.STATUS_NORMAL
|
||||
.equals(msgInner.getStatus()) ? "发布" : "保存") + "消息成功!"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
*/
|
||||
package com.jeesite.modules.sys.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.jeesite.common.dao.CrudDao;
|
||||
import com.jeesite.common.mybatis.annotation.MyBatisDao;
|
||||
import com.jeesite.modules.sys.entity.EmpUser;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工管理DAO接口
|
||||
* @author ThinkGem
|
||||
@@ -20,6 +20,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@ConditionalOnProperty(name="user.enabled", havingValue="true", matchIfMissing=true)
|
||||
public interface EmpUserDao extends CrudDao<EmpUser> {
|
||||
|
||||
// @Override
|
||||
// @Results({
|
||||
// @Result(column = "mobile", property = "mobile",
|
||||
// javaType = String.class, typeHandler = AesTypeHandler.class)
|
||||
// })
|
||||
// @SelectProvider(type = SelectSqlProvider.class, method = "get")
|
||||
// EmpUser get(EmpUser entity);
|
||||
|
||||
/**
|
||||
* 查询全部用户,仅返回基本信息
|
||||
*/
|
||||
|
||||
@@ -18,4 +18,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@ConditionalOnProperty(name="user.enabled", havingValue="true", matchIfMissing=true)
|
||||
public interface LogDao extends CrudDao<Log> {
|
||||
|
||||
/**
|
||||
* 删除某个日期之前创建的日志
|
||||
* @param log .createDate
|
||||
*/
|
||||
int deleteLogBefore(Log log);
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -27,6 +27,10 @@ import javax.validation.Valid;
|
||||
* @version 2017-03-25
|
||||
*/
|
||||
@Table(name="${_prefix}sys_user", alias="a", label="员工信息", columns={
|
||||
// 手机号加密脱敏例子,共同打开 EmpUserDao.java 和 EmpUserDao.xml 中的 result 注释
|
||||
// 详细 typeHandler 用法,请看文档:https://jeesite.com/docs/dao-mybatis/#手机号加密脱敏
|
||||
// @Column(name="mobile", attrName="mobile", label="手机号码", queryType=QueryType.EQ,
|
||||
// javaType = String.class, typeHandler = AesTypeHandler.class),
|
||||
@Column(includeEntity=User.class),
|
||||
}, joinTable={
|
||||
@JoinTable(type=Type.JOIN, entity=Employee.class, alias="e",
|
||||
@@ -42,35 +46,35 @@ import javax.validation.Valid;
|
||||
@JoinTable(type=Type.LEFT_JOIN, entity=Office.class, alias="o",
|
||||
on="o.office_code=e.office_code", attrName="employee.office",
|
||||
columns={
|
||||
@Column(includeEntity=DataEntity.class),
|
||||
@Column(includeEntity=TreeEntity.class),
|
||||
@Column(name="office_code", label="机构编码", isPK=true),
|
||||
@Column(name="view_code", label="机构代码"),
|
||||
@Column(name="office_name", label="机构名称", isQuery=false),
|
||||
@Column(name="full_name", label="机构全称"),
|
||||
@Column(name="office_type", label="机构类型"),
|
||||
@Column(name="leader", label="负责人"),
|
||||
@Column(name="phone", label="电话"),
|
||||
@Column(name="address", label="联系地址"),
|
||||
@Column(name="zip_code", label="邮政编码"),
|
||||
@Column(name="email", label="邮箱"),
|
||||
@Column(includeEntity=DataEntity.class),
|
||||
@Column(includeEntity=TreeEntity.class),
|
||||
@Column(name="office_code", label="机构编码", isPK=true),
|
||||
@Column(name="view_code", label="机构代码"),
|
||||
@Column(name="office_name", label="机构名称", isQuery=false),
|
||||
@Column(name="full_name", label="机构全称"),
|
||||
@Column(name="office_type", label="机构类型"),
|
||||
@Column(name="leader", label="负责人"),
|
||||
@Column(name="phone", label="电话"),
|
||||
@Column(name="address", label="联系地址"),
|
||||
@Column(name="zip_code", label="邮政编码"),
|
||||
@Column(name="email", label="邮箱"),
|
||||
}),
|
||||
@JoinTable(type=Type.LEFT_JOIN, entity=Company.class, alias="c",
|
||||
on="c.company_code=e.company_code", attrName="employee.company",
|
||||
columns={
|
||||
@Column(includeEntity=DataEntity.class),
|
||||
@Column(includeEntity=TreeEntity.class),
|
||||
@Column(name="company_code", label="公司编码", isPK=true),
|
||||
@Column(name="view_code", label="公司代码"),
|
||||
@Column(name="company_name", label="公司名称", isQuery=false),
|
||||
@Column(name="full_name", label="公司全称"),
|
||||
@Column(includeEntity=DataEntity.class),
|
||||
@Column(includeEntity=TreeEntity.class),
|
||||
@Column(name="company_code", label="公司编码", isPK=true),
|
||||
@Column(name="view_code", label="公司代码"),
|
||||
@Column(name="company_name", label="公司名称", isQuery=false),
|
||||
@Column(name="full_name", label="公司全称"),
|
||||
}),
|
||||
@JoinTable(type=Type.LEFT_JOIN, entity=Area.class, alias="ar",
|
||||
on="ar.area_code = c.area_code", attrName="employee.company.area",
|
||||
columns={
|
||||
@Column(name="area_code", label="区域代码", isPK=true),
|
||||
@Column(name="area_name", label="区域名称", isQuery=false),
|
||||
@Column(name="area_type", label="区域类型"),
|
||||
@Column(name="area_code", label="区域代码", isPK=true),
|
||||
@Column(name="area_name", label="区域名称", isQuery=false),
|
||||
@Column(name="area_type", label="区域类型"),
|
||||
}),
|
||||
// @JoinTable(type=Type.LEFT_JOIN, entity=User.class, attrName="this", alias="u",
|
||||
// on="u.user_code = a.create_by", columns={
|
||||
|
||||
@@ -6,6 +6,7 @@ package com.jeesite.modules.sys.entity;
|
||||
|
||||
import com.jeesite.common.entity.DataEntity;
|
||||
import com.jeesite.common.mybatis.annotation.Column;
|
||||
import com.jeesite.common.mybatis.annotation.JoinTable;
|
||||
import com.jeesite.common.mybatis.annotation.Table;
|
||||
|
||||
/**
|
||||
@@ -16,6 +17,19 @@ import com.jeesite.common.mybatis.annotation.Table;
|
||||
@Table(name="${_prefix}sys_employee_post", alias="a", columns={
|
||||
@Column(name="emp_code", attrName="empCode", label="员工编码", isPK=true),
|
||||
@Column(name="post_code", attrName="postCode", label="岗位编码", isPK=true),
|
||||
},
|
||||
joinTable={
|
||||
@JoinTable(type=JoinTable.Type.LEFT_JOIN, entity=Post.class, alias="p", lazy = true,
|
||||
on="a.post_code = p.post_code", attrName="post",
|
||||
columns={
|
||||
@Column(name="post_code", attrName="postCode", label="岗位编码", isPK=true),
|
||||
@Column(name="post_name", attrName="postName", label="岗位名称"),
|
||||
}),
|
||||
@JoinTable(type=JoinTable.Type.JOIN, entity=User.class, alias="u", lazy = true,
|
||||
on="a.emp_code = u.ref_code AND u.user_type='employee'", attrName="this",
|
||||
columns={
|
||||
@Column(name="user_code", attrName="userCode", label="用户编码", isPK=true),
|
||||
})
|
||||
}, orderBy=""
|
||||
)
|
||||
public class EmployeePost extends DataEntity<EmployeePost> {
|
||||
@@ -23,7 +37,11 @@ public class EmployeePost extends DataEntity<EmployeePost> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String empCode; // 员工编码
|
||||
private String postCode; // 岗位编码
|
||||
|
||||
|
||||
private Post post; // sqlMap().loadJoinTableAlias("p") 的时候返回数据
|
||||
|
||||
private String userCode; // 根据用户编码查询 sqlMap().loadJoinTableAlias("p,u") 的时候有效
|
||||
|
||||
public EmployeePost() {
|
||||
this(null, null);
|
||||
}
|
||||
@@ -48,5 +66,20 @@ public class EmployeePost extends DataEntity<EmployeePost> {
|
||||
public void setPostCode(String postCode) {
|
||||
this.postCode = postCode;
|
||||
}
|
||||
|
||||
|
||||
public Post getPost() {
|
||||
return post;
|
||||
}
|
||||
|
||||
public void setPost(Post post) {
|
||||
this.post = post;
|
||||
}
|
||||
|
||||
public String getUserCode() {
|
||||
return userCode;
|
||||
}
|
||||
|
||||
public void setUserCode(String userCode) {
|
||||
this.userCode = userCode;
|
||||
}
|
||||
}
|
||||
@@ -240,7 +240,7 @@ public class Log extends DataEntity<Log> {
|
||||
|
||||
/**
|
||||
* 设置请求参数
|
||||
* @param paramMap
|
||||
* @param paramsMap
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void setRequestParams(Map paramsMap){
|
||||
|
||||
@@ -35,6 +35,7 @@ public class Post extends DataEntity<Post> {
|
||||
private Integer postSort; // 岗位排序(升序)
|
||||
|
||||
private String empCode; // 根据用户查询岗位
|
||||
private String userCode; // 根据用户编码查询
|
||||
|
||||
private String roleCodes; // 关联的角色编号
|
||||
private String roleNames; // 关联的角色名称
|
||||
@@ -110,6 +111,16 @@ public class Post extends DataEntity<Post> {
|
||||
this.empCode = empCode;
|
||||
}
|
||||
|
||||
@ApiModelProperty("根据用户编码查询")
|
||||
public String getUserCode() {
|
||||
return userCode;
|
||||
}
|
||||
|
||||
public void setUserCode(String userCode) {
|
||||
this.userCode = userCode;
|
||||
}
|
||||
|
||||
@ApiModelProperty("岗位绑定角色编码")
|
||||
public String getRoleCodes() {
|
||||
return roleCodes;
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ import com.jeesite.common.mybatis.annotation.Table;
|
||||
@Column(name="role_code", attrName="roleCode", label="角色编码", isPK=true),
|
||||
@Column(name="post_code", attrName="postCode", label="岗位编码", isPK=true),
|
||||
},
|
||||
joinTable = {
|
||||
joinTable={
|
||||
@JoinTable(type=JoinTable.Type.LEFT_JOIN, entity=Role.class, alias="r", lazy = true,
|
||||
on="a.role_code = r.role_code", attrName="role",
|
||||
columns={
|
||||
@Column(name="role_code", attrName="roleCode", label="角色编码", isPK=true),
|
||||
@Column(name="role_name", attrName="roleName", label="角色名称"),
|
||||
@Column(name="role_code", attrName="roleCode", label="角色编码", isPK=true),
|
||||
@Column(name="role_name", attrName="roleName", label="角色名称"),
|
||||
})
|
||||
}, orderBy=""
|
||||
)
|
||||
@@ -33,7 +33,7 @@ public class PostRole extends DataEntity<PostRole> {
|
||||
private String postCode; // 岗位编码
|
||||
private String roleCode; // 角色编码
|
||||
|
||||
private Role role; // sqlMap().loadJoinTableAlias("r")的时候返回数据
|
||||
private Role role; // sqlMap().loadJoinTableAlias("r") 的时候返回数据
|
||||
|
||||
public PostRole() {
|
||||
this(null, null);
|
||||
|
||||
@@ -4,14 +4,6 @@
|
||||
*/
|
||||
package com.jeesite.modules.sys.interceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.jeesite.common.idgen.IdGen;
|
||||
import com.jeesite.common.lang.ByteUtils;
|
||||
import com.jeesite.common.lang.StringUtils;
|
||||
@@ -20,6 +12,13 @@ import com.jeesite.common.network.IpUtils;
|
||||
import com.jeesite.common.service.BaseService;
|
||||
import com.jeesite.modules.sys.utils.LogUtils;
|
||||
import com.jeesite.modules.sys.utils.UserUtils;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 日志拦截器
|
||||
@@ -36,7 +35,7 @@ public class LogInterceptor extends BaseService implements HandlerInterceptor {
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
if (StringUtils.isBlank(MDC.get(TRACE_ID))) {
|
||||
MDC.put(TRACE_ID, IdGen.nextId());
|
||||
MDC.put(TRACE_ID, IdGen.randomBase62(4));
|
||||
}
|
||||
long beginTime = System.currentTimeMillis();// 1、开始时间
|
||||
startTimeThreadLocal.set(beginTime); // 线程绑定变量(该数据只有当前请求的线程可见)
|
||||
|
||||
@@ -25,5 +25,13 @@ public interface LogService extends CrudServiceApi<Log> {
|
||||
* 不使用数据库事务,执行插入日志
|
||||
*/
|
||||
void insertLog(Log entity);
|
||||
|
||||
|
||||
/**
|
||||
* 清理指定日期之前的日志(可新建job定时调用)
|
||||
* 1、清理1年前的所有日志:logService.deleteLogBefore(1, 0, 0);
|
||||
* 2、清理6个月前的所有日志:logService.deleteLogBefore(0, 6, 0);
|
||||
* 3、清理7天前的所有日志:logService.deleteLogBefore(0, 0, 7);
|
||||
* 4、清理1年6个月前的所有日志:logService.deleteLogBefore(1, 6, 0);
|
||||
*/
|
||||
void deleteLogBefore(Integer year, Integer months, Integer days);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,14 @@ public class EmpUserServiceSupport extends CrudService<EmpUserDao, EmpUser>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
*/
|
||||
@Override
|
||||
public List<EmpUser> findList(EmpUser entity) {
|
||||
return super.findList(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询数据
|
||||
*/
|
||||
|
||||
@@ -49,7 +49,15 @@ public class EmployeeServiceSupport extends CrudService<EmployeeDao, Employee>
|
||||
where.setEmpNo(employee.getEmpNo());
|
||||
return dao.getByEntity(where);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
*/
|
||||
@Override
|
||||
public List<Employee> findList(Employee entity) {
|
||||
return super.findList(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询分页数据
|
||||
*/
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
*/
|
||||
package com.jeesite.modules.sys.service.support;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.jeesite.common.datasource.DataSourceHolder;
|
||||
import com.jeesite.common.entity.Page;
|
||||
import com.jeesite.common.lang.DateUtils;
|
||||
import com.jeesite.common.service.CrudService;
|
||||
import com.jeesite.modules.sys.dao.LogDao;
|
||||
import com.jeesite.modules.sys.entity.Log;
|
||||
@@ -50,4 +53,30 @@ public class LogServiceSupport extends CrudService<LogDao, Log>
|
||||
dao.insert(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理指定日期之前的日志(可新建job定时调用)
|
||||
* 1、清理1年前的所有日志:logService.deleteLogBefore(1, 0, 0);
|
||||
* 2、清理6个月前的所有日志:logService.deleteLogBefore(0, 6, 0);
|
||||
* 3、清理7天前的所有日志:logService.deleteLogBefore(0, 0, 7);
|
||||
* 4、清理1年6个月前的所有日志:logService.deleteLogBefore(1, 6, 0);
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteLogBefore(Integer year, Integer months, Integer days) {
|
||||
Date date = DateUtils.getOfDayLast(new Date());
|
||||
if (year != null && year != 0) {
|
||||
date = DateUtils.addYears(date, -year);
|
||||
}
|
||||
if (months != null && months != 0) {
|
||||
date = DateUtils.addMonths(date, -months);
|
||||
}
|
||||
if (days != null && days != 0) {
|
||||
date = DateUtils.addDays(date, -days);
|
||||
}
|
||||
Log log = new Log();
|
||||
log.setCreateDate(date);
|
||||
dao.deleteLogBefore(log);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -50,6 +50,14 @@ public class PostServiceSupport extends CrudService<PostDao, Post>
|
||||
return dao.getByEntity(where);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据
|
||||
*/
|
||||
@Override
|
||||
public List<Post> findList(Post entity) {
|
||||
return super.findList(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询岗位
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.jeesite.common.web.BaseController;
|
||||
import com.jeesite.common.web.CookieUtils;
|
||||
import com.jeesite.common.web.http.ServletUtils;
|
||||
import com.jeesite.modules.sys.entity.Menu;
|
||||
import com.jeesite.modules.sys.entity.Role;
|
||||
import com.jeesite.modules.sys.entity.User;
|
||||
import com.jeesite.modules.sys.utils.PwdUtils;
|
||||
import com.jeesite.modules.sys.utils.UserUtils;
|
||||
@@ -107,9 +108,8 @@ public class LoginController extends BaseController{
|
||||
*/
|
||||
@RequestMapping(value = "loginFailure")
|
||||
public String loginFailure(HttpServletRequest request, HttpServletResponse response, Model model) {
|
||||
LoginInfo loginInfo = UserUtils.getLoginInfo();
|
||||
|
||||
// 如果已经登录,则跳转到管理首页
|
||||
// // 如果已经登录,则跳转到管理首页
|
||||
// LoginInfo loginInfo = UserUtils.getLoginInfo();
|
||||
// if(loginInfo != null){ // 注释掉,已经登录的账号,正常返回登录失败信息,方便前端判断。
|
||||
// String queryString = request.getQueryString();
|
||||
// queryString = queryString == null ? "" : "?" + queryString;
|
||||
@@ -188,7 +188,7 @@ public class LoginController extends BaseController{
|
||||
|
||||
// 获取当前会话对象,并返回一些数据
|
||||
Session session = UserUtils.getSession();
|
||||
model.addAllAttributes(FormFilter.getLoginSuccessData(user, session));
|
||||
model.addAllAttributes(FormFilter.getLoginSuccessData(request, response, user, session));
|
||||
|
||||
// 是否是登录操作
|
||||
boolean isLogin = Global.TRUE.equals(session.getAttribute(BaseAuthorizingRealm.IS_LOGIN_OPER));
|
||||
@@ -204,6 +204,23 @@ public class LoginController extends BaseController{
|
||||
if (loginInfo.getParam("lang") != null){
|
||||
Global.setLang(loginInfo.getParam("lang"), request, response);
|
||||
}
|
||||
// 根据当前用户子系统,切换到默认系统下
|
||||
for(Role role : user.getRoleList()) {
|
||||
if (role.getSysCodes() != null) {
|
||||
String sysCode = null;
|
||||
for (String code : StringUtils.splitComma(role.getSysCodes())) {
|
||||
if (StringUtils.isNotBlank(code)) {
|
||||
sysCode = code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sysCode != null) {
|
||||
session.setAttribute("sysCode", sysCode);
|
||||
UserUtils.removeCache(UserUtils.CACHE_AUTH_INFO+"_"+session.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取登录成功后跳转的页面
|
||||
|
||||
@@ -67,7 +67,7 @@ public class OnlineController extends BaseController{
|
||||
public String list(Model model) {
|
||||
return "modules/sys/onlineList";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在线用户列表数据
|
||||
* @author ThinkGem
|
||||
@@ -75,12 +75,12 @@ public class OnlineController extends BaseController{
|
||||
@RequiresPermissions("sys:online:view")
|
||||
@RequestMapping(value = "listData")
|
||||
@ResponseBody
|
||||
public List<Map<String, Object>> listData(String isAllOnline, String isVisitor, String sessionId,
|
||||
public List<Map<String, Object>> listData(String isAllOnline, String isVisitor, String sessionId,
|
||||
String userCode, String userName, String userType, String orderBy) {
|
||||
List<Map<String, Object>> list = ListUtils.newArrayList();
|
||||
boolean excludeLeave = !Global.YES.equals(isAllOnline);
|
||||
boolean excludeVisitor = !Global.YES.equals(isVisitor);
|
||||
Collection<Session> sessions = sessionDAO.getActiveSessions(excludeLeave,
|
||||
Collection<Session> sessions = sessionDAO.getActiveSessions(excludeLeave,
|
||||
excludeVisitor, null, sessionId, userCode);
|
||||
long currentTime = System.currentTimeMillis();
|
||||
for (Session session : sessions){
|
||||
@@ -93,10 +93,11 @@ public class OnlineController extends BaseController{
|
||||
Map<String, Object> map = MapUtils.newLinkedHashMap();
|
||||
// 为了安全性,需要有权限的人才能看
|
||||
if (UserUtils.getSubject().isPermitted("sys:online:edit")){
|
||||
map.put("id", session.getId().toString());
|
||||
map.put("id", session.getId().toString());
|
||||
}
|
||||
map.put("startTimestamp", DateUtils.formatDateTime(session.getStartTimestamp()));
|
||||
map.put("lastAccessTime", DateUtils.formatDateTime(session.getLastAccessTime()));
|
||||
map.put("timeoutLong", session.getTimeout()-(currentTime-session.getLastAccessTime().getTime()));
|
||||
map.put("timeout", TimeUtils.formatTime(session.getTimeout()-(currentTime-session.getLastAccessTime().getTime())));
|
||||
map.put("userCode", session.getAttribute("userCode"));
|
||||
map.put("userName", session.getAttribute("userName"));
|
||||
@@ -109,18 +110,27 @@ public class OnlineController extends BaseController{
|
||||
if (StringUtils.isBlank(orderBy)){
|
||||
orderBy = "lastAccessTime desc";
|
||||
}
|
||||
orderBy = StringUtils.replace(orderBy, "timeout", "timeoutLong");
|
||||
final String[] ss = orderBy.trim().split(" ");
|
||||
if (ss.length == 2){
|
||||
list.sort((o1, o2) -> {
|
||||
String s1 = (String) o1.get(ss[0]);
|
||||
String s2 = (String) o2.get(ss[0]);
|
||||
Object s1 = o1.get(ss[0]);
|
||||
Object s2 = o2.get(ss[0]);
|
||||
if (s1 == null || s2 == null) {
|
||||
return -1;
|
||||
}
|
||||
if ("asc".equals(ss[1])) {
|
||||
return s1.compareTo(s2);
|
||||
} else {
|
||||
return s2.compareTo(s1);
|
||||
if (StringUtils.endsWith(ss[0], "Long")) {
|
||||
if ("asc".equals(ss[1])) {
|
||||
return ((Long)s1).compareTo((Long)s2);
|
||||
} else {
|
||||
return ((Long)s2).compareTo((Long)s1);
|
||||
}
|
||||
}else{
|
||||
if ("asc".equals(ss[1])) {
|
||||
return ((String)s1).compareTo((String)s2);
|
||||
} else {
|
||||
return ((String)s2).compareTo((String)s1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -135,6 +145,9 @@ public class OnlineController extends BaseController{
|
||||
@RequestMapping(value = "tickOut")
|
||||
@ResponseBody
|
||||
public String kickOut(String sessionId) {
|
||||
if (Global.isDemoMode()){
|
||||
return renderResult(Global.FALSE, "演示模式,不允许操作!");
|
||||
}
|
||||
Session session = sessionDAO.readSession(sessionId);
|
||||
if (session != null){
|
||||
Map<String, String> onlineTickOutMap = SysCacheUtils.get("onlineTickOutMap");
|
||||
|
||||
@@ -4,29 +4,6 @@
|
||||
*/
|
||||
package com.jeesite.modules.sys.web.user;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import com.alibaba.fastjson.JSONValidator;
|
||||
import com.jeesite.common.codec.EncodeUtils;
|
||||
import com.jeesite.common.collect.ListUtils;
|
||||
@@ -41,20 +18,28 @@ import com.jeesite.common.shiro.realm.AuthorizingRealm;
|
||||
import com.jeesite.common.utils.excel.ExcelExport;
|
||||
import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
|
||||
import com.jeesite.common.web.BaseController;
|
||||
import com.jeesite.modules.sys.entity.EmpUser;
|
||||
import com.jeesite.modules.sys.entity.Employee;
|
||||
import com.jeesite.modules.sys.entity.Post;
|
||||
import com.jeesite.modules.sys.entity.Role;
|
||||
import com.jeesite.modules.sys.entity.User;
|
||||
import com.jeesite.modules.sys.entity.UserDataScope;
|
||||
import com.jeesite.modules.sys.service.EmpUserService;
|
||||
import com.jeesite.modules.sys.service.EmployeeService;
|
||||
import com.jeesite.modules.sys.service.PostService;
|
||||
import com.jeesite.modules.sys.service.RoleService;
|
||||
import com.jeesite.modules.sys.service.UserService;
|
||||
import com.jeesite.modules.sys.entity.*;
|
||||
import com.jeesite.modules.sys.service.*;
|
||||
import com.jeesite.modules.sys.utils.EmpUtils;
|
||||
import com.jeesite.modules.sys.utils.ModuleUtils;
|
||||
import com.jeesite.modules.sys.utils.UserUtils;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 员工用户Controller
|
||||
@@ -279,19 +264,20 @@ public class EmpUserController extends BaseController {
|
||||
@RequiresPermissions("sys:empUser:updateStatus")
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "disable")
|
||||
public String disable(EmpUser empUser) {
|
||||
public String disable(EmpUser empUser, boolean freeze) {
|
||||
if (User.isSuperAdmin(empUser.getUserCode())) {
|
||||
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
|
||||
}
|
||||
if (!EmpUser.USER_TYPE_EMPLOYEE.equals(empUser.getUserType())){
|
||||
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
|
||||
}
|
||||
String text = freeze ? "冻结" : "停用";
|
||||
if (empUser.currentUser().getUserCode().equals(empUser.getUserCode())) {
|
||||
return renderResult(Global.FALSE, text("停用用户失败,不允许停用当前用户"));
|
||||
return renderResult(Global.FALSE, text(text + "用户失败,不允许" + text + "当前用户"));
|
||||
}
|
||||
empUser.setStatus(User.STATUS_DISABLE);
|
||||
empUser.setStatus(freeze ? User.STATUS_FREEZE : User.STATUS_DISABLE);
|
||||
empUserService.updateStatus(empUser);
|
||||
return renderResult(Global.TRUE, text("停用用户''{0}''成功", empUser.getUserName()));
|
||||
return renderResult(Global.TRUE, text(text + "用户''{0}''成功", empUser.getUserName()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,17 +288,18 @@ public class EmpUserController extends BaseController {
|
||||
@RequiresPermissions("sys:empUser:updateStatus")
|
||||
@ResponseBody
|
||||
@RequestMapping(value = "enable")
|
||||
public String enable(EmpUser empUser) {
|
||||
public String enable(EmpUser empUser, boolean freeze) {
|
||||
if (User.isSuperAdmin(empUser.getUserCode())) {
|
||||
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
|
||||
}
|
||||
if (!EmpUser.USER_TYPE_EMPLOYEE.equals(empUser.getUserType())){
|
||||
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
|
||||
}
|
||||
String text = freeze ? "解冻" : "启用";
|
||||
empUser.setStatus(User.STATUS_NORMAL);
|
||||
empUserService.updateStatus(empUser);
|
||||
AuthorizingRealm.isValidCodeLogin(empUser.getLoginCode(), empUser.getCorpCode_(), null, "success");
|
||||
return renderResult(Global.TRUE, text("启用用户''{0}''成功", empUser.getUserName()));
|
||||
return renderResult(Global.TRUE, text(text + "用户''{0}''成功", empUser.getUserName()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
com.jeesite.autoconfigure.core.ShiroAutoConfiguration
|
||||
com.jeesite.autoconfigure.sys.SysAutoConfiguration
|
||||
@@ -27,6 +27,10 @@ jdbc:
|
||||
|
||||
# 获取连接等待超时时间,单位毫秒(1分钟)(4.0.6+)
|
||||
maxWait: 60000
|
||||
|
||||
# 连接超时参数,单位毫秒 (v5.5.2+)
|
||||
connectTimeout: ~
|
||||
socketTimeout: ~
|
||||
|
||||
# 从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个(4.0.6+)
|
||||
testOnBorrow: false
|
||||
@@ -47,7 +51,7 @@ jdbc:
|
||||
removeAbandoned: false
|
||||
removeAbandonedTimeout: 2100
|
||||
|
||||
# Oracle 下会自动开启 PSCache,并指定每个连接上 PSCache 大小。若不指定,则与 maxActive 相同(4.1.5+)
|
||||
# 是否缓存 PreparedStatement 对象的最大数量(4.1.5+)
|
||||
maxPoolPreparedStatementPerConnectionSize: ~
|
||||
|
||||
# 设置连接属性,可获取到表的 remark (备注)
|
||||
@@ -402,7 +406,7 @@ shiro:
|
||||
# 允许跨域访问时 CORS,可以获取和返回的方法和请求头
|
||||
#accessControlAllowMethods: GET, POST, OPTIONS
|
||||
#accessControlAllowHeaders: content-type, x-requested-with, x-ajax, x-token, x-remember
|
||||
#accessControlExposeHeaders: x-remember
|
||||
#accessControlExposeHeaders: x-token, x-remember
|
||||
|
||||
# 是否允许接收跨域的Cookie凭证数据 CORS
|
||||
#accessControlAllowCredentials: false
|
||||
@@ -416,8 +420,8 @@ shiro:
|
||||
# 是否在登录后生成新的Session(默认false)
|
||||
isGenerateNewSessionAfterLogin: false
|
||||
|
||||
# 内部系统访问过滤器,可设置多个允许的内部系统IP地址串,多个用逗号隔开
|
||||
innerFilterAllowRemoteAddrs: 127.0.0.1
|
||||
# 内部系统访问过滤器,可设置多个允许的内部系统IP地址串,多个用逗号隔开,完整的IP使用“]”符号结尾
|
||||
innerFilterAllowRemoteAddrs: 127.0.0.1]
|
||||
|
||||
# URI 权限过滤器定义(自定义添加参数时,请不要移除 ${adminPath}/** = user,否则会导致权限异常)
|
||||
# 提示:填写过滤规则,请注意先后顺序,从上到下,先匹配先受用规则,匹配成功后不再继续匹配。
|
||||
@@ -447,6 +451,9 @@ shiro:
|
||||
/userfiles/** = anon
|
||||
/validCode = anon
|
||||
/static/** = anon
|
||||
/oauth2/login/** = anon
|
||||
/oauth2/binder/** = anon
|
||||
/oauth2/callback/** = anon
|
||||
/oauth2/authorize = user
|
||||
/druid/** = perms[sys:state:druid]
|
||||
/bpm/modeler/** = perms[bpm:modeler]
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
<logger name="com.atomikos.recovery.xa.XaResourceRecoveryManager" level="ERROR" />
|
||||
<logger name="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator" level="DEBUG" />
|
||||
<!-- <logger name="org.springframework.transaction.support.TransactionSynchronizationManager" level="TRACE" /> -->
|
||||
|
||||
<logger name="org.springframework.web.servlet.PageNotFound" level="ERROR" />
|
||||
|
||||
<logger name="springfox.documentation.spring.web.readers.parameter.ParameterDataTypeReader" level="ERROR" />
|
||||
<logger name="springfox.documentation.schema.property.CachingModelPropertiesProvider" level="ERROR" />
|
||||
<!-- <logger name="io.swagger" level="DEBUG" /> -->
|
||||
|
||||
@@ -476,6 +476,8 @@ CREATE TABLE ${_prefix}sys_module
|
||||
main_class_name varchar(500),
|
||||
current_version varchar(50),
|
||||
upgrade_info varchar(300),
|
||||
gen_base_dir vargraphic(1000),
|
||||
tpl_category varchar(200),
|
||||
status char(1) DEFAULT '0' NOT NULL,
|
||||
create_by varchar(64) NOT NULL,
|
||||
create_date timestamp NOT NULL,
|
||||
|
||||
@@ -1,63 +1,62 @@
|
||||
-- tables_db2_v95.sql
|
||||
|
||||
create table ${_prefix}job_job_details(
|
||||
sched_name varchar(120) not null,
|
||||
job_name varchar(80) not null,
|
||||
job_group varchar(80) not null,
|
||||
description varchar(120),
|
||||
job_class_name varchar(128) not null,
|
||||
is_durable integer not null,
|
||||
is_nonconcurrent integer not null,
|
||||
is_update_data integer not null,
|
||||
requests_recovery integer not null,
|
||||
job_data blob(2000),
|
||||
primary key (sched_name,job_name,job_group)
|
||||
sched_name varchar(120) not null,
|
||||
job_name varchar(80) not null,
|
||||
job_group varchar(80) not null,
|
||||
description varchar(120),
|
||||
job_class_name varchar(128) not null,
|
||||
is_durable integer not null,
|
||||
is_nonconcurrent integer not null,
|
||||
is_update_data integer not null,
|
||||
requests_recovery integer not null,
|
||||
job_data blob(2000),
|
||||
primary key (sched_name,job_name,job_group)
|
||||
);
|
||||
|
||||
create table ${_prefix}job_triggers(
|
||||
sched_name varchar(120) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
job_name varchar(80) not null,
|
||||
job_group varchar(80) not null,
|
||||
description varchar(120),
|
||||
next_fire_time bigint,
|
||||
prev_fire_time bigint,
|
||||
priority integer,
|
||||
trigger_state varchar(16) not null,
|
||||
trigger_type varchar(8) not null,
|
||||
start_time bigint not null,
|
||||
end_time bigint,
|
||||
calendar_name varchar(80),
|
||||
misfire_instr smallint,
|
||||
job_data blob(2000),
|
||||
primary key (sched_name,trigger_name,trigger_group),
|
||||
foreign key (sched_name,job_name,job_group) references ${_prefix}job_job_details(sched_name,job_name,job_group)
|
||||
sched_name varchar(120) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
job_name varchar(80) not null,
|
||||
job_group varchar(80) not null,
|
||||
description varchar(120),
|
||||
next_fire_time bigint,
|
||||
prev_fire_time bigint,
|
||||
priority integer,
|
||||
trigger_state varchar(16) not null,
|
||||
trigger_type varchar(8) not null,
|
||||
start_time bigint not null,
|
||||
end_time bigint,
|
||||
calendar_name varchar(80),
|
||||
misfire_instr smallint,
|
||||
job_data blob(2000),
|
||||
primary key (sched_name,trigger_name,trigger_group),
|
||||
foreign key (sched_name,job_name,job_group) references ${_prefix}job_job_details(sched_name,job_name,job_group)
|
||||
);
|
||||
|
||||
create table ${_prefix}job_simple_triggers(
|
||||
sched_name varchar(120) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
repeat_count bigint not null,
|
||||
repeat_interval bigint not null,
|
||||
times_triggered bigint not null,
|
||||
primary key (sched_name,trigger_name,trigger_group),
|
||||
foreign key (sched_name,trigger_name,trigger_group) references ${_prefix}job_triggers(sched_name,trigger_name,trigger_group)
|
||||
sched_name varchar(120) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
repeat_count bigint not null,
|
||||
repeat_interval bigint not null,
|
||||
times_triggered bigint not null,
|
||||
primary key (sched_name,trigger_name,trigger_group),
|
||||
foreign key (sched_name,trigger_name,trigger_group) references ${_prefix}job_triggers(sched_name,trigger_name,trigger_group)
|
||||
);
|
||||
|
||||
create table ${_prefix}job_cron_triggers(
|
||||
sched_name varchar(120) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
cron_expression varchar(120) not null,
|
||||
time_zone_id varchar(80),
|
||||
primary key (sched_name,trigger_name,trigger_group),
|
||||
foreign key (sched_name,trigger_name,trigger_group) references ${_prefix}job_triggers(sched_name,trigger_name,trigger_group)
|
||||
sched_name varchar(120) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
cron_expression varchar(120) not null,
|
||||
time_zone_id varchar(80),
|
||||
primary key (sched_name,trigger_name,trigger_group),
|
||||
foreign key (sched_name,trigger_name,trigger_group) references ${_prefix}job_triggers(sched_name,trigger_name,trigger_group)
|
||||
);
|
||||
|
||||
CREATE TABLE ${_prefix}job_simprop_triggers
|
||||
(
|
||||
CREATE TABLE ${_prefix}job_simprop_triggers(
|
||||
sched_name varchar(120) not null,
|
||||
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||
@@ -78,54 +77,54 @@ CREATE TABLE ${_prefix}job_simprop_triggers
|
||||
);
|
||||
|
||||
create table ${_prefix}job_blob_triggers(
|
||||
sched_name varchar(120) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
blob_data blob(2000),
|
||||
primary key (sched_name,trigger_name,trigger_group),
|
||||
foreign key (sched_name,trigger_name,trigger_group) references ${_prefix}job_triggers(sched_name,trigger_name,trigger_group)
|
||||
sched_name varchar(120) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
blob_data blob(2000),
|
||||
primary key (sched_name,trigger_name,trigger_group),
|
||||
foreign key (sched_name,trigger_name,trigger_group) references ${_prefix}job_triggers(sched_name,trigger_name,trigger_group)
|
||||
);
|
||||
|
||||
create table ${_prefix}job_calendars(
|
||||
sched_name varchar(120) not null,
|
||||
calendar_name varchar(80) not null,
|
||||
calendar blob(2000) not null,
|
||||
primary key (calendar_name)
|
||||
sched_name varchar(120) not null,
|
||||
calendar_name varchar(80) not null,
|
||||
calendar blob(2000) not null,
|
||||
primary key (calendar_name)
|
||||
);
|
||||
|
||||
create table ${_prefix}job_fired_triggers(
|
||||
sched_name varchar(120) not null,
|
||||
entry_id varchar(95) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
instance_name varchar(80) not null,
|
||||
fired_time bigint not null,
|
||||
sched_time bigint not null,
|
||||
priority integer not null,
|
||||
state varchar(16) not null,
|
||||
job_name varchar(80),
|
||||
job_group varchar(80),
|
||||
is_nonconcurrent integer,
|
||||
requests_recovery integer,
|
||||
primary key (sched_name,entry_id)
|
||||
sched_name varchar(120) not null,
|
||||
entry_id varchar(95) not null,
|
||||
trigger_name varchar(80) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
instance_name varchar(80) not null,
|
||||
fired_time bigint not null,
|
||||
sched_time bigint not null,
|
||||
priority integer not null,
|
||||
state varchar(16) not null,
|
||||
job_name varchar(80),
|
||||
job_group varchar(80),
|
||||
is_nonconcurrent integer,
|
||||
requests_recovery integer,
|
||||
primary key (sched_name,entry_id)
|
||||
);
|
||||
|
||||
create table ${_prefix}job_paused_trigger_grps(
|
||||
sched_name varchar(120) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
primary key (sched_name,trigger_group)
|
||||
sched_name varchar(120) not null,
|
||||
trigger_group varchar(80) not null,
|
||||
primary key (sched_name,trigger_group)
|
||||
);
|
||||
|
||||
create table ${_prefix}job_scheduler_state(
|
||||
sched_name varchar(120) not null,
|
||||
instance_name varchar(80) not null,
|
||||
last_checkin_time bigint not null,
|
||||
checkin_interval bigint not null,
|
||||
primary key (sched_name,instance_name)
|
||||
sched_name varchar(120) not null,
|
||||
instance_name varchar(80) not null,
|
||||
last_checkin_time bigint not null,
|
||||
checkin_interval bigint not null,
|
||||
primary key (sched_name,instance_name)
|
||||
);
|
||||
|
||||
create table ${_prefix}job_locks(
|
||||
sched_name varchar(120) not null,
|
||||
lock_name varchar(40) not null,
|
||||
primary key (sched_name,lock_name)
|
||||
sched_name varchar(120) not null,
|
||||
lock_name varchar(40) not null,
|
||||
primary key (sched_name,lock_name)
|
||||
);
|
||||
|
||||
@@ -476,6 +476,8 @@ CREATE TABLE ${_prefix}sys_module
|
||||
main_class_name varchar(500),
|
||||
current_version varchar(50),
|
||||
upgrade_info varchar(300),
|
||||
gen_base_dir varchar(1000),
|
||||
tpl_category varchar(200),
|
||||
status char(1) DEFAULT '0' NOT NULL,
|
||||
create_by varchar(64) NOT NULL,
|
||||
create_date datetime NOT NULL,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user