68 Commits
v2.0 ... v2.1

Author SHA1 Message Date
RuoYi
cca4eeae72 若依 2.1 2020-08-02 09:59:55 +08:00
RuoYi
bf544deeaa 表格工具栏右侧添加刷新&显隐查询栏 2020-08-01 19:25:18 +08:00
RuoYi
a9a1200e77 升级vue-cli版本到4.4.4 2020-08-01 19:09:08 +08:00
RuoYi
43bc0ca39b OAuth自动刷新续签Token 2020-08-01 18:28:30 +08:00
RuoYi
c0251e5cda 修复验证码异常时network面板的中文会出现乱码问题 2020-07-31 15:32:54 +08:00
RuoYi
56ea7c9caf 代码生成支持自定义路径 2020-07-31 11:45:27 +08:00
RuoYi
17d5751452 表单类型为Integer/Long设置整形默认值 2020-07-30 21:50:01 +08:00
RuoYi
8b5a16c692 权限修正(角色导出权限) 2020-07-30 21:46:24 +08:00
RuoYi
5524d5a0bc 修改 node-sass 为 dart-sass 2020-07-30 21:44:53 +08:00
RuoYi
40696a10e3 excel 导入数字不需要格式化 ,导入允许列和属性个数不一致 2020-07-30 21:42:34 +08:00
RuoYi
9bfe3e5328 Excel支持分割字符串组内容 2020-07-30 21:23:42 +08:00
RuoYi
165a957d67 代码生成支持复选框 2020-07-30 21:17:54 +08:00
RuoYi
4a48702ccb 检查字符支持小数点&降级改成异常提醒 2020-07-30 18:30:30 +08:00
RuoYi
41cf67da6d 验证码类型支持(数组计算、字符验证) 2020-07-30 18:26:52 +08:00
RuoYi
4126f634ba 优化selectDictLabel方法,数组迭代器换为some 2020-07-30 18:14:51 +08:00
RuoYi
337f6fd3db 修复 utils/index.js 中不包含 parseTime 函数的 bug 2020-07-30 18:12:39 +08:00
RuoYi
8ae4f5e90b 代码生成支持选择上级菜单 2020-07-30 18:09:44 +08:00
RuoYi
7e2b00b98b 代码生成查询条件修正 2020-07-30 17:33:54 +08:00
RuoYi
57200e5f5d 禁止加密密文返回前端 2020-07-30 17:30:50 +08:00
RuoYi
bb5b7466db 升级element-ui版本到2.13.2 2020-07-30 17:29:17 +08:00
RuoYi
c7908e1b8e 删除babel,提高编译速度。 2020-07-30 17:26:47 +08:00
RuoYi
76aa1cda49 新增菜单默认主类目 2020-07-30 17:24:41 +08:00
RuoYi
59b8df2e90 定时任务cron表达式验证 2020-07-30 17:16:05 +08:00
RuoYi
5967f7f11b 验证码高度调整 2020-07-30 16:48:00 +08:00
若依
3ad7742838 !12 修改import引入语句缺少分号问题
Merge pull request !12 from jingfeng/master
2020-07-22 16:02:26 +08:00
jingfeng
3a400df707 update ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm.
修改import引入语句缺少分号问题
2020-07-21 14:26:08 +08:00
RuoYi
4a608d4d21 添加新群号 2020-07-13 09:21:48 +08:00
RuoYi
d9ebddc669 防止切换权限用户后登录出现404 2020-07-11 09:42:25 +08:00
RuoYi
7ecba12d3e 角色权限修改时已有权限未自动勾选异常修复 2020-07-11 09:41:30 +08:00
RuoYi
30aa0c4fca 修复客户端模式认证会出现错误 2020-07-11 09:20:13 +08:00
若依
99e1dfccf5 !9 RedisCache中所有方法参数添加final,并优化list取出效率,添加其它常用redis方法
Merge pull request !9 from 心悦李国楠/dev-心悦
2020-07-11 09:00:46 +08:00
RuoYi
d0fe6f3462 权限配置自动注册 2020-07-10 15:53:34 +08:00
RuoYi
c404c280f7 Excel支持sort导出排序 2020-07-10 15:12:20 +08:00
RuoYi
7bdd20ec24 修改文件编码格式utf-8 2020-07-04 15:59:53 +08:00
心悦李国楠
e0ba2ba3c5 RedisCache中所有方法参数添加final,并优化list取出效率,添加其它常用redis方法 2020-07-03 14:24:33 +08:00
RuoYi
e76d087b21 终端设置更新缓存 2020-07-02 20:26:04 +08:00
RuoYi
394bde5e8e 终端设置安全码加密 2020-07-02 20:25:11 +08:00
RuoYi
ad690bac17 修复头像上传成功二次打开无法改变裁剪框大小和位置问题 2020-07-02 16:18:07 +08:00
RuoYi
e056ab0cc2 修复布局为small者mini用户表单显示错位问题 2020-07-02 16:14:16 +08:00
RuoYi
7549c904f2 修复代码生成点击多次表修改数据不变化的问题 2020-07-02 16:12:03 +08:00
RuoYi
0788a57bec 修复代码生成导入表结构出现异常页面不提醒问题 2020-07-02 16:09:07 +08:00
RuoYi
eb48d6a80f 创建用户不允许选择系统管理员角色 2020-07-02 16:02:00 +08:00
RuoYi
1b70ef990b 全局异常处理(网关异常&业务异常) 2020-07-02 15:51:45 +08:00
RuoYi
e48d75afcd 修复Enter键搜索时是刷新页面而不是查询列表 2020-07-02 09:26:06 +08:00
RuoYi
c91194f848 Feign配置自动注册 2020-06-27 22:01:27 +08:00
RuoYi
a90b576116 删除job重复表单参数 2020-06-19 22:19:51 +08:00
Sxile
9aee5142fd 修复注释与参数名称不对应 2020-06-19 17:30:39 +08:00
Sxile
230d4170e1 添加缺少的@Override 2020-06-19 17:28:36 +08:00
Sxile
2c250c1d1b 添加{}使代码更容易理解 2020-06-19 17:26:37 +08:00
Sxile
7302189208 常量接口修改为常量类 2020-06-19 17:24:33 +08:00
Sxile
a40d691e31 添加@Component注解 2020-06-19 17:18:49 +08:00
Sxile
719e1fdfa9 添加@Component注解 2020-06-19 17:18:05 +08:00
Sxile
5734607e03 删除多余的代码 2020-06-19 16:40:01 +08:00
Sxile
e6e673e9b4 删除已经注释掉的代码 2020-06-19 16:09:27 +08:00
Sxile
6eda1dee45 常量接口修改为常量类 2020-06-19 16:05:51 +08:00
RuoYi
ff3bc4b25e 代码生成浮点型改用BigDecimal 2020-06-18 18:54:20 +08:00
RuoYi
aa13a1d88e 修改用户管理复选框宽度,防止部分浏览器出现省略号 2020-06-18 18:48:52 +08:00
RuoYi
beaf17ddd2 修正定时任务日志权限字符 2020-06-18 18:47:34 +08:00
RuoYi
029fe5c63f 添加Jackson时区配置 2020-06-18 18:28:00 +08:00
RuoYi
bea2f32781 修正代码生成时间工具类包路径 2020-06-18 17:45:12 +08:00
RuoYi
3b88fe2b6f 更新nacos配置脚本 2020-06-18 17:38:16 +08:00
RuoYi
97a0326abd 修改树表代码生成模板 2020-06-14 15:39:43 +08:00
RuoYi
83460dfcb6 修改单表代码生成模板 2020-06-14 15:30:58 +08:00
RuoYi
6ee4efa284 自定义oauth2返回异常信息 2020-06-14 14:47:47 +08:00
RuoYi
1c06db8999 升级nacos到最新版1.3.0 全新内核构建 2020-06-13 12:32:47 +08:00
若依
5fa7b3f579 !6 修正【代码生成】功能无法下载的问题
Merge pull request !6 from 覃盛春/master
2020-06-13 12:03:15 +08:00
RuoYi
bb305dfb6f 网关支持黑名单配置 2020-06-13 11:54:53 +08:00
qinsc
5585a4e807 * 修正【代码生成】无法下载的Bug,主要是URL并接少了斜杠导致URL路径不对; 2020-06-11 18:42:56 +08:00
134 changed files with 1960 additions and 794 deletions

View File

@@ -4,8 +4,8 @@
* 后端采用Spring Boot、Spring Cloud & Alibaba。 * 后端采用Spring Boot、Spring Cloud & Alibaba。
* 注册中心、配置中心选型Nacos权限认证使用OAuth2。 * 注册中心、配置中心选型Nacos权限认证使用OAuth2。
* 流量控制框架选型Sentinel。 * 流量控制框架选型Sentinel。
* 感谢[ruoyi-cloud-design](https://gitee.com/zhangmrit/ruoyi-cloud)[pig](https://gitee.com/log4j/pig)。
* 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi),如需分离应用,请移步 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) * 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi),如需分离应用,请移步 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)
* 感谢[ruoyi-cloud-design](https://gitee.com/zhangmrit/ruoyi-cloud)[pig](https://gitee.com/log4j/pig)。
* 阿里云优惠券:[点我进入](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)   * 阿里云优惠券:[点我进入](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)  
@@ -74,27 +74,27 @@ com.ruoyi
<td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/707825ad3f29de74a8d6d02fbd73ad631ea.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/46be40cc6f01aa300eed53a19b5012bf484.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/4284796d4cea240d181b8f2201813dda710.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/3ecfac87a049f7fe36abbcaafb2c40d36cf.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/71c2d48905221a09a728df4aff4160b8607.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/c14c1ee9a64a6a9c2c22f67d43198767dbe.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/fdea1d8bb8625c27bf964176a2c8ebc6945.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/509d2708cfd762b6e6339364cac1cc1970c.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-f1fd681cc9d295db74e85ad6d2fe4389454.png"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
</tr> </tr>
<tr> <tr>
@@ -110,4 +110,4 @@ com.ruoyi
## 若依微服务交流群 ## 若依微服务交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/42799195-blue.svg)](https://jq.qq.com/?_wv=1027&k=yqInfq0S) 点击按钮入群。 QQ群 [![加入QQ群](https://img.shields.io/badge/已满-42799195-blue.svg)](https://jq.qq.com/?_wv=1027&k=yqInfq0S) [![加入QQ群](https://img.shields.io/badge/170157040-blue.svg)](https://jq.qq.com/?_wv=1027&k=Oy1mb3p8) 点击按钮入群。

12
pom.xml
View File

@@ -6,14 +6,14 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
<name>ruoyi</name> <name>ruoyi</name>
<url>http://www.ruoyi.vip</url> <url>http://www.ruoyi.vip</url>
<description>若依微服务系统</description> <description>若依微服务系统</description>
<properties> <properties>
<ruoyi.version>2.0.0</ruoyi.version> <ruoyi.version>2.1.0</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
@@ -21,6 +21,7 @@
<spring-cloud.version>Hoxton.SR4</spring-cloud.version> <spring-cloud.version>Hoxton.SR4</spring-cloud.version>
<spring-boot-admin.version>2.2.3</spring-boot-admin.version> <spring-boot-admin.version>2.2.3</spring-boot-admin.version>
<spring-boot.mybatis>2.1.2</spring-boot.mybatis> <spring-boot.mybatis>2.1.2</spring-boot.mybatis>
<nacos.version>1.3.0</nacos.version>
<swagger.fox.version>2.9.2</swagger.fox.version> <swagger.fox.version>2.9.2</swagger.fox.version>
<swagger.core.version>1.5.24</swagger.core.version> <swagger.core.version>1.5.24</swagger.core.version>
<kaptcha.version>2.3.2</kaptcha.version> <kaptcha.version>2.3.2</kaptcha.version>
@@ -55,6 +56,13 @@
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<!-- Alibaba Nacos 配置 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
<!-- SpringBoot 依赖配置 --> <!-- SpringBoot 依赖配置 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-api</artifactId> <artifactId>ruoyi-api</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -11,13 +11,11 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
@@ -118,22 +116,16 @@ public class AuthServerConfig extends AuthorizationServerConfigurerAdapter
@Bean @Bean
public TokenEnhancer tokenEnhancer() public TokenEnhancer tokenEnhancer()
{ {
return new TokenEnhancer() return (accessToken, authentication) -> {
{ if (authentication.getUserAuthentication() != null)
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication)
{ {
if (accessToken instanceof DefaultOAuth2AccessToken) Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>();
{ LoginUser user = (LoginUser) authentication.getUserAuthentication().getPrincipal();
DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken; additionalInformation.put(SecurityConstants.DETAILS_USER_ID, user.getUserId());
LoginUser user = (LoginUser) authentication.getUserAuthentication().getPrincipal(); additionalInformation.put(SecurityConstants.DETAILS_USERNAME, user.getUsername());
Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>(); ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
additionalInformation.put(SecurityConstants.DETAILS_USERNAME, authentication.getName()); }
additionalInformation.put(SecurityConstants.DETAILS_USER_ID, user.getUserId()); return accessToken;
token.setAdditionalInformation(additionalInformation);
}
return accessToken;
};
}; };
} }
} }

View File

@@ -0,0 +1,20 @@
package com.ruoyi.auth.exception;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
/**
* oauth2自定义异常
*
* @author ruoyi
**/
@JsonSerialize(using = CustomOauthExceptionSerializer.class)
public class CustomOauthException extends OAuth2Exception
{
private static final long serialVersionUID = 1L;
public CustomOauthException(String msg)
{
super(msg);
}
}

View File

@@ -0,0 +1,48 @@
package com.ruoyi.auth.exception;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
/**
* 自定义异常返回
*
* @author ruoyi
**/
public class CustomOauthExceptionSerializer extends StdSerializer<CustomOauthException>
{
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(CustomOauthExceptionSerializer.class);
public static final String BAD_CREDENTIALS = "Bad credentials";
public CustomOauthExceptionSerializer()
{
super(CustomOauthException.class);
}
@Override
public void serialize(CustomOauthException e, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException
{
jsonGenerator.writeStartObject();
jsonGenerator.writeNumberField(AjaxResult.CODE_TAG, HttpStatus.ERROR);
if (StringUtils.equals(e.getMessage(), BAD_CREDENTIALS))
{
jsonGenerator.writeStringField(AjaxResult.MSG_TAG, "用户名或密码错误");
}
else
{
log.warn("oauth2 认证异常 {} ", e);
jsonGenerator.writeStringField(AjaxResult.MSG_TAG, e.getMessage());
}
jsonGenerator.writeEndObject();
}
}

View File

@@ -1,6 +1,6 @@
package com.ruoyi.auth.exception; package com.ruoyi.auth.exception;
import javax.servlet.http.HttpServletResponse; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator; import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
@@ -15,7 +15,6 @@ public class CustomWebResponseExceptionTranslator implements WebResponseExceptio
@Override @Override
public ResponseEntity<OAuth2Exception> translate(Exception e) public ResponseEntity<OAuth2Exception> translate(Exception e)
{ {
OAuth2Exception oAuth2Exception = (OAuth2Exception) e; return ResponseEntity.status(HttpStatus.OK).body(new CustomOauthException(e.getMessage()));
return ResponseEntity.status(HttpServletResponse.SC_UNAUTHORIZED).body(oAuth2Exception);
} }
} }

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -14,6 +14,11 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
public @interface Excel public @interface Excel
{ {
/**
* 导出时在excel中排序
*/
public int sort() default Integer.MAX_VALUE;
/** /**
* 导出到Excel中的名字. * 导出到Excel中的名字.
*/ */
@@ -29,6 +34,11 @@ public @interface Excel
*/ */
public String readConverterExp() default ""; public String readConverterExp() default "";
/**
* 分隔符,读取字符串组内容
*/
public String separator() default ",";
/** /**
* 导出类型0数字 1字符串 * 导出类型0数字 1字符串
*/ */

View File

@@ -31,10 +31,11 @@ public class Constants
* 成功标记 * 成功标记
*/ */
public static final Integer SUCCESS = 200; public static final Integer SUCCESS = 200;
/** /**
* 失败标记 * 失败标记
*/ */
public static final Integer FAIL = 501; public static final Integer FAIL = 500;
/** /**
* 登录成功 * 登录成功

View File

@@ -22,6 +22,12 @@ public class GenConstants
/** 树名称字段 */ /** 树名称字段 */
public static final String TREE_NAME = "treeName"; public static final String TREE_NAME = "treeName";
/** 上级菜单ID字段 */
public static final String PARENT_MENU_ID = "parentMenuId";
/** 上级菜单名称字段 */
public static final String PARENT_MENU_NAME = "parentMenuName";
/** 数据库字符串类型 */ /** 数据库字符串类型 */
public static final String[] COLUMNTYPE_STR = { "char", "varchar", "narchar", "varchar2", "tinytext", "text", public static final String[] COLUMNTYPE_STR = { "char", "varchar", "narchar", "varchar2", "tinytext", "text",
"mediumtext", "longtext" }; "mediumtext", "longtext" };

View File

@@ -5,7 +5,7 @@ package com.ruoyi.common.core.constant;
* *
* @author ruoyi * @author ruoyi
*/ */
public interface HttpStatus public class HttpStatus
{ {
/** /**
* 操作成功 * 操作成功

View File

@@ -5,7 +5,7 @@ package com.ruoyi.common.core.constant;
* *
* @author ruoyi * @author ruoyi
*/ */
public interface ScheduleConstants public class ScheduleConstants
{ {
public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME"; public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";

View File

@@ -5,7 +5,7 @@ package com.ruoyi.common.core.constant;
* *
* @author ruoyi * @author ruoyi
*/ */
public interface ServiceNameConstants public class ServiceNameConstants
{ {
/** /**
* 认证服务的serviceid * 认证服务的serviceid

View File

@@ -12,6 +12,12 @@ public class R<T> implements Serializable
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 成功 */
public static final int SUCCESS = Constants.SUCCESS;
/** 失败 */
public static final int FAIL = Constants.FAIL;
private int code; private int code;
private String msg; private String msg;
@@ -20,40 +26,40 @@ public class R<T> implements Serializable
public static <T> R<T> ok() public static <T> R<T> ok()
{ {
return restResult(null, Constants.SUCCESS, null); return restResult(null, SUCCESS, null);
} }
public static <T> R<T> ok(T data) public static <T> R<T> ok(T data)
{ {
return restResult(data, Constants.SUCCESS, null); return restResult(data, SUCCESS, null);
} }
public static <T> R<T> ok(T data, String msg) public static <T> R<T> ok(T data, String msg)
{ {
return restResult(data, Constants.SUCCESS, msg); return restResult(data, SUCCESS, msg);
} }
public static <T> R<T> failed() public static <T> R<T> fail()
{ {
return restResult(null, Constants.FAIL, null); return restResult(null, FAIL, null);
} }
public static <T> R<T> failed(String msg) public static <T> R<T> fail(String msg)
{ {
return restResult(null, Constants.FAIL, msg); return restResult(null, FAIL, msg);
} }
public static <T> R<T> failed(T data) public static <T> R<T> fail(T data)
{ {
return restResult(data, Constants.FAIL, null); return restResult(data, FAIL, null);
} }
public static <T> R<T> failed(T data, String msg) public static <T> R<T> fail(T data, String msg)
{ {
return restResult(data, Constants.FAIL, msg); return restResult(data, FAIL, msg);
} }
public static <T> R<T> failed(int code, String msg) public static <T> R<T> fail(int code, String msg)
{ {
return restResult(null, code, msg); return restResult(null, code, msg);
} }

View File

@@ -376,6 +376,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
* *
* @return UUID 的哈希码值。 * @return UUID 的哈希码值。
*/ */
@Override
public int hashCode() public int hashCode()
{ {
long hilo = mostSigBits ^ leastSigBits; long hilo = mostSigBits ^ leastSigBits;
@@ -391,6 +392,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
* *
* @return 如果对象相同,则返回 {@code true};否则返回 {@code false} * @return 如果对象相同,则返回 {@code true};否则返回 {@code false}
*/ */
@Override
public boolean equals(Object obj) public boolean equals(Object obj)
{ {
if ((null == obj) || (obj.getClass() != UUID.class)) if ((null == obj) || (obj.getClass() != UUID.class))
@@ -414,6 +416,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
* @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。 * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。
* *
*/ */
@Override
public int compareTo(UUID val) public int compareTo(UUID val)
{ {
// The ordering is intentionally set up so that the UUIDs // The ordering is intentionally set up so that the UUIDs

View File

@@ -0,0 +1,142 @@
package com.ruoyi.common.core.utils.file;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletRequest;
/**
* 文件处理工具类
*
* @author ruoyi
*/
public class FileUtils extends org.apache.commons.io.FileUtils
{
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
/**
* 输出指定文件的byte数组
*
* @param filePath 文件路径
* @param os 输出流
* @return
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException
{
FileInputStream fis = null;
try
{
File file = new File(filePath);
if (!file.exists())
{
throw new FileNotFoundException(filePath);
}
fis = new FileInputStream(file);
byte[] b = new byte[1024];
int length;
while ((length = fis.read(b)) > 0)
{
os.write(b, 0, length);
}
}
catch (IOException e)
{
throw e;
}
finally
{
if (os != null)
{
try
{
os.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if (fis != null)
{
try
{
fis.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
/**
* 删除文件
*
* @param filePath 文件
* @return
*/
public static boolean deleteFile(String filePath)
{
boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists())
{
file.delete();
flag = true;
}
return flag;
}
/**
* 文件名称验证
*
* @param filename 文件名称
* @return true 正常 false 非法
*/
public static boolean isValidFilename(String filename)
{
return filename.matches(FILENAME_PATTERN);
}
/**
* 下载文件名重新编码
*
* @param request 请求对象
* @param fileName 文件名
* @return 编码后的文件名
*/
public static String setFileDownloadHeader(HttpServletRequest request, String fileName)
throws UnsupportedEncodingException
{
final String agent = request.getHeader("USER-AGENT");
String filename = fileName;
if (agent.contains("MSIE"))
{
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
}
else if (agent.contains("Firefox"))
{
// 火狐浏览器
filename = new String(fileName.getBytes(), "ISO8859-1");
}
else if (agent.contains("Chrome"))
{
// google浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
else
{
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}

View File

@@ -110,8 +110,9 @@ public class IpUtils
{ {
case 1: case 1:
l = Long.parseLong(elements[0]); l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L)) if ((l < 0L) || (l > 4294967295L)){
return null; return null;
}
bytes[0] = (byte) (int) (l >> 24 & 0xFF); bytes[0] = (byte) (int) (l >> 24 & 0xFF);
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
@@ -119,12 +120,14 @@ public class IpUtils
break; break;
case 2: case 2:
l = Integer.parseInt(elements[0]); l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L)) if ((l < 0L) || (l > 255L)) {
return null; return null;
}
bytes[0] = (byte) (int) (l & 0xFF); bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]); l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L)) if ((l < 0L) || (l > 16777215L)) {
return null; return null;
}
bytes[1] = (byte) (int) (l >> 16 & 0xFF); bytes[1] = (byte) (int) (l >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF); bytes[3] = (byte) (int) (l & 0xFF);
@@ -133,13 +136,15 @@ public class IpUtils
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
{ {
l = Integer.parseInt(elements[i]); l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) if ((l < 0L) || (l > 255L)) {
return null; return null;
}
bytes[i] = (byte) (int) (l & 0xFF); bytes[i] = (byte) (int) (l & 0xFF);
} }
l = Integer.parseInt(elements[2]); l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L)) if ((l < 0L) || (l > 65535L)) {
return null; return null;
}
bytes[2] = (byte) (int) (l >> 8 & 0xFF); bytes[2] = (byte) (int) (l >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF); bytes[3] = (byte) (int) (l & 0xFF);
break; break;
@@ -147,8 +152,9 @@ public class IpUtils
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
{ {
l = Integer.parseInt(elements[i]); l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) if ((l < 0L) || (l > 255L)) {
return null; return null;
}
bytes[i] = (byte) (int) (l & 0xFF); bytes[i] = (byte) (int) (l & 0xFF);
} }
break; break;

View File

@@ -6,13 +6,14 @@ import java.io.OutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.BorderStyle;
@@ -192,7 +193,10 @@ public class ExcelUtil<T>
// 设置类的私有字段属性可访问. // 设置类的私有字段属性可访问.
field.setAccessible(true); field.setAccessible(true);
Integer column = cellMap.get(attr.name()); Integer column = cellMap.get(attr.name());
fieldsMap.put(column, field); if (column != null)
{
fieldsMap.put(column, field);
}
} }
} }
for (int i = 1; i < rows; i++) for (int i = 1; i < rows; i++)
@@ -263,7 +267,7 @@ public class ExcelUtil<T>
} }
else if (StringUtils.isNotEmpty(attr.readConverterExp())) else if (StringUtils.isNotEmpty(attr.readConverterExp()))
{ {
val = reverseByExp(String.valueOf(val), attr.readConverterExp()); val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
} }
ReflectUtils.invokeSetter(entity, propertyName, val); ReflectUtils.invokeSetter(entity, propertyName, val);
} }
@@ -523,13 +527,14 @@ public class ExcelUtil<T>
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
String dateFormat = attr.dateFormat(); String dateFormat = attr.dateFormat();
String readConverterExp = attr.readConverterExp(); String readConverterExp = attr.readConverterExp();
String separator = attr.separator();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{ {
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
} }
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
{ {
cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp)); cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
} }
else else
{ {
@@ -607,28 +612,36 @@ public class ExcelUtil<T>
* *
* @param propertyValue 参数值 * @param propertyValue 参数值
* @param converterExp 翻译注解 * @param converterExp 翻译注解
* @param separator 分隔符
* @return 解析后值 * @return 解析后值
* @throws Exception
*/ */
public static String convertByExp(String propertyValue, String converterExp) throws Exception public static String convertByExp(String propertyValue, String converterExp, String separator)
{ {
try StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{ {
String[] convertSource = converterExp.split(","); String[] itemArray = item.split("=");
for (String item : convertSource) if (StringUtils.containsAny(separator, propertyValue))
{
for (String value : propertyValue.split(separator))
{
if (itemArray[0].equals(value))
{
propertyString.append(itemArray[1] + separator);
break;
}
}
}
else
{ {
String[] itemArray = item.split("=");
if (itemArray[0].equals(propertyValue)) if (itemArray[0].equals(propertyValue))
{ {
return itemArray[1]; return itemArray[1];
} }
} }
} }
catch (Exception e) return StringUtils.stripEnd(propertyString.toString(), separator);
{
throw e;
}
return propertyValue;
} }
/** /**
@@ -636,28 +649,36 @@ public class ExcelUtil<T>
* *
* @param propertyValue 参数值 * @param propertyValue 参数值
* @param converterExp 翻译注解 * @param converterExp 翻译注解
* @param separator 分隔符
* @return 解析后值 * @return 解析后值
* @throws Exception
*/ */
public static String reverseByExp(String propertyValue, String converterExp) throws Exception public static String reverseByExp(String propertyValue, String converterExp, String separator)
{ {
try StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{ {
String[] convertSource = converterExp.split(","); String[] itemArray = item.split("=");
for (String item : convertSource) if (StringUtils.containsAny(separator, propertyValue))
{
for (String value : propertyValue.split(separator))
{
if (itemArray[1].equals(value))
{
propertyString.append(itemArray[0] + separator);
break;
}
}
}
else
{ {
String[] itemArray = item.split("=");
if (itemArray[1].equals(propertyValue)) if (itemArray[1].equals(propertyValue))
{ {
return itemArray[0]; return itemArray[0];
} }
} }
} }
catch (Exception e) return StringUtils.stripEnd(propertyString.toString(), separator);
{
throw e;
}
return propertyValue;
} }
/** /**
@@ -739,6 +760,7 @@ public class ExcelUtil<T>
} }
} }
} }
this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
} }
/** /**
@@ -809,14 +831,7 @@ public class ExcelUtil<T>
} }
else else
{ {
if ((Double) val % 1 > 0) val = new BigDecimal(val.toString()); // 浮点格式处理
{
val = new DecimalFormat("0.00").format(val);
}
else
{
val = new DecimalFormat("0").format(val);
}
} }
} }
else if (cell.getCellTypeEnum() == CellType.STRING) else if (cell.getCellTypeEnum() == CellType.STRING)

View File

@@ -1,5 +1,6 @@
package com.ruoyi.common.core.utils.sql; package com.ruoyi.common.core.utils.sql;
import com.ruoyi.common.core.exception.BaseException;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
/** /**
@@ -10,9 +11,9 @@ import com.ruoyi.common.core.utils.StringUtils;
public class SqlUtil public class SqlUtil
{ {
/** /**
* 仅支持字母、数字、下划线、空格、逗号(支持多个字段排序) * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
*/ */
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,]+"; public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/** /**
* 检查字符,防止注入绕过 * 检查字符,防止注入绕过
@@ -21,7 +22,7 @@ public class SqlUtil
{ {
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
{ {
return StringUtils.EMPTY; throw new BaseException("参数不符合规范,不能进行查询");
} }
return value; return value;
} }

View File

@@ -0,0 +1,79 @@
package com.ruoyi.common.core.web.domain;
import java.util.ArrayList;
import java.util.List;
/**
* Tree基类
*
* @author ruoyi
*/
public class TreeEntity extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 父菜单名称 */
private String parentName;
/** 父菜单ID */
private Long parentId;
/** 显示顺序 */
private Integer orderNum;
/** 祖级列表 */
private String ancestors;
/** 子部门 */
private List<?> children = new ArrayList<>();
public String getParentName()
{
return parentName;
}
public void setParentName(String parentName)
{
this.parentName = parentName;
}
public Long getParentId()
{
return parentId;
}
public void setParentId(Long parentId)
{
this.parentId = parentId;
}
public Integer getOrderNum()
{
return orderNum;
}
public void setOrderNum(Integer orderNum)
{
this.orderNum = orderNum;
}
public String getAncestors()
{
return ancestors;
}
public void setAncestors(String ancestors)
{
this.ancestors = ancestors;
}
public List<?> getChildren()
{
return children;
}
public void setChildren(List<?> children)
{
this.children = children;
}
}

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -98,7 +98,8 @@ public class DataScopeAspect
* *
* @param joinPoint 切点 * @param joinPoint 切点
* @param user 用户 * @param user 用户
* @param alias 别名 * @param deptAlias 部门别名
* @param userAlias 用户别名
*/ */
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
{ {

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -198,8 +198,14 @@ public class LogAspect
{ {
if (!isFilterObject(paramsArray[i])) if (!isFilterObject(paramsArray[i]))
{ {
Object jsonObj = JSON.toJSON(paramsArray[i]); try
params += jsonObj.toString() + " "; {
Object jsonObj = JSON.toJSON(paramsArray[i]);
params += jsonObj.toString() + " ";
}
catch (Exception e)
{
}
} }
} }
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -36,6 +36,7 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
this.clazz = clazz; this.clazz = clazz;
} }
@Override
public byte[] serialize(T t) throws SerializationException public byte[] serialize(T t) throws SerializationException
{ {
if (t == null) if (t == null)
@@ -45,6 +46,7 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
} }
@Override
public T deserialize(byte[] bytes) throws SerializationException public T deserialize(byte[] bytes) throws SerializationException
{ {
if (bytes == null || bytes.length <= 0) if (bytes == null || bytes.length <= 0)

View File

@@ -1,17 +1,12 @@
package com.ruoyi.common.redis.service; package com.ruoyi.common.redis.service;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -33,13 +28,10 @@ public class RedisService
* *
* @param key 缓存的键值 * @param key 缓存的键值
* @param value 缓存的值 * @param value 缓存的值
* @return 缓存的对象
*/ */
public <T> ValueOperations<String, T> setCacheObject(String key, T value) public <T> void setCacheObject(final String key, final T value)
{ {
ValueOperations<String, T> operation = redisTemplate.opsForValue(); redisTemplate.opsForValue().set(key, value);
operation.set(key, value);
return operation;
} }
/** /**
@@ -49,13 +41,35 @@ public class RedisService
* @param value 缓存的值 * @param value 缓存的值
* @param timeout 时间 * @param timeout 时间
* @param timeUnit 时间颗粒度 * @param timeUnit 时间颗粒度
* @return 缓存的对象
*/ */
public <T> ValueOperations<String, T> setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit) public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
{ {
ValueOperations<String, T> operation = redisTemplate.opsForValue(); redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
operation.set(key, value, timeout, timeUnit); }
return operation;
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功false=设置失败
*/
public boolean expire(final String key, final long timeout)
{
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit)
{
return redisTemplate.expire(key, timeout, unit);
} }
/** /**
@@ -64,7 +78,7 @@ public class RedisService
* @param key 缓存键值 * @param key 缓存键值
* @return 缓存键值对应的数据 * @return 缓存键值对应的数据
*/ */
public <T> T getCacheObject(String key) public <T> T getCacheObject(final String key)
{ {
ValueOperations<String, T> operation = redisTemplate.opsForValue(); ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key); return operation.get(key);
@@ -75,19 +89,20 @@ public class RedisService
* *
* @param key * @param key
*/ */
public void deleteObject(String key) public boolean deleteObject(final String key)
{ {
redisTemplate.delete(key); return redisTemplate.delete(key);
} }
/** /**
* 删除集合对象 * 删除集合对象
* *
* @param collection * @param collection 多个对象
* @return
*/ */
public void deleteObject(Collection collection) public long deleteObject(final Collection collection)
{ {
redisTemplate.delete(collection); return redisTemplate.delete(collection);
} }
/** /**
@@ -97,18 +112,10 @@ public class RedisService
* @param dataList 待缓存的List数据 * @param dataList 待缓存的List数据
* @return 缓存的对象 * @return 缓存的对象
*/ */
public <T> ListOperations<String, T> setCacheList(String key, List<T> dataList) public <T> long setCacheList(final String key, final List<T> dataList)
{ {
ListOperations listOperation = redisTemplate.opsForList(); Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
if (null != dataList) return count == null ? 0 : count;
{
int size = dataList.size();
for (int i = 0; i < size; i++)
{
listOperation.leftPush(key, dataList.get(i));
}
}
return listOperation;
} }
/** /**
@@ -117,17 +124,9 @@ public class RedisService
* @param key 缓存的键值 * @param key 缓存的键值
* @return 缓存键值对应的数据 * @return 缓存键值对应的数据
*/ */
public <T> List<T> getCacheList(String key) public <T> List<T> getCacheList(final String key)
{ {
List<T> dataList = new ArrayList<T>(); return redisTemplate.opsForList().range(key, 0, -1);
ListOperations<String, T> listOperation = redisTemplate.opsForList();
Long size = listOperation.size(key);
for (int i = 0; i < size; i++)
{
dataList.add(listOperation.index(key, i));
}
return dataList;
} }
/** /**
@@ -137,15 +136,10 @@ public class RedisService
* @param dataSet 缓存的数据 * @param dataSet 缓存的数据
* @return 缓存数据的对象 * @return 缓存数据的对象
*/ */
public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> dataSet) public <T> long setCacheSet(final String key, final Set<T> dataSet)
{ {
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); Long count = redisTemplate.opsForSet().add(key, dataSet);
Iterator<T> it = dataSet.iterator(); return count == null ? 0 : count;
while (it.hasNext())
{
setOperation.add(it.next());
}
return setOperation;
} }
/** /**
@@ -154,12 +148,9 @@ public class RedisService
* @param key * @param key
* @return * @return
*/ */
public <T> Set<T> getCacheSet(String key) public <T> Set<T> getCacheSet(final String key)
{ {
Set<T> dataSet = new HashSet<T>(); return redisTemplate.opsForSet().members(key);
BoundSetOperations<String, T> operation = redisTemplate.boundSetOps(key);
dataSet = operation.members();
return dataSet;
} }
/** /**
@@ -167,19 +158,12 @@ public class RedisService
* *
* @param key * @param key
* @param dataMap * @param dataMap
* @return
*/ */
public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> dataMap) public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
{ {
HashOperations hashOperations = redisTemplate.opsForHash(); if (dataMap != null) {
if (null != dataMap) redisTemplate.opsForHash().putAll(key, dataMap);
{
for (Map.Entry<String, T> entry : dataMap.entrySet())
{
hashOperations.put(key, entry.getKey(), entry.getValue());
}
} }
return hashOperations;
} }
/** /**
@@ -188,10 +172,46 @@ public class RedisService
* @param key * @param key
* @return * @return
*/ */
public <T> Map<String, T> getCacheMap(String key) public <T> Map<String, T> getCacheMap(final String key)
{ {
Map<String, T> map = redisTemplate.opsForHash().entries(key); return redisTemplate.opsForHash().entries(key);
return map; }
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value)
{
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey)
{
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
{
return redisTemplate.opsForHash().multiGet(key, hKeys);
} }
/** /**
@@ -200,7 +220,7 @@ public class RedisService
* @param pattern 字符串前缀 * @param pattern 字符串前缀
* @return 对象列表 * @return 对象列表
*/ */
public Collection<String> keys(String pattern) public Collection<String> keys(final String pattern)
{ {
return redisTemplate.keys(pattern); return redisTemplate.keys(pattern);
} }

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -1,15 +1,12 @@
package com.ruoyi.common.security.annotation; package com.ruoyi.common.security.annotation;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import com.ruoyi.common.security.feign.OAuth2FeignConfig;
import com.ruoyi.common.security.config.ApplicationConfig;
import com.ruoyi.common.security.config.SecurityImportBeanDefinitionRegistrar; import com.ruoyi.common.security.config.SecurityImportBeanDefinitionRegistrar;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@@ -23,7 +20,7 @@ import com.ruoyi.common.security.config.SecurityImportBeanDefinitionRegistrar;
// 开启线程异步执行 // 开启线程异步执行
@EnableAsync @EnableAsync
// 自动加载类 // 自动加载类
@Import(SecurityImportBeanDefinitionRegistrar.class) @Import({ SecurityImportBeanDefinitionRegistrar.class, OAuth2FeignConfig.class, ApplicationConfig.class })
public @interface EnableCustomConfig public @interface EnableCustomConfig
{ {

View File

@@ -0,0 +1,22 @@
package com.ruoyi.common.security.config;
import java.util.TimeZone;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
/**
* 系统配置
*
* @author ruoyi
*/
public class ApplicationConfig
{
/**
* 时区配置
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
{
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
}
}

View File

@@ -4,12 +4,14 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Configurable; import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/** /**
* 忽略服务间的认证 * 忽略服务间的认证
* *
* @author ruoyi * @author ruoyi
**/ **/
@Component
@Configurable @Configurable
@ConfigurationProperties(prefix = "security.oauth2.ignore") @ConfigurationProperties(prefix = "security.oauth2.ignore")
public class AuthIgnoreConfig public class AuthIgnoreConfig

View File

@@ -0,0 +1,27 @@
package com.ruoyi.common.security.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
/**
*
* @EnableGlobalMethodSecurity(securedEnabled=true)
* 开启@Secured 注解过滤权限
*
* @EnableGlobalMethodSecurity(jsr250Enabled=true)
* 开启@RolesAllowed 注解过滤权限
*
* @EnableGlobalMethodSecurity(prePostEnabled=true)
* 使用表达式时间方法级别的安全性 4个注解可用
* -@PreAuthorize 在方法调用之前,基于表达式的计算结果来限制对方法的访问
* -@PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
* -@PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果
* -@PreFilter 允许方法调用,但必须在进入方法之前过滤输入值
*
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig
{
}

View File

@@ -28,6 +28,6 @@ public class CustomAccessDeniedHandler extends OAuth2AccessDeniedHandler
logger.info("权限不足,请联系管理员 {}", request.getRequestURI()); logger.info("权限不足,请联系管理员 {}", request.getRequestURI());
String msg = authException.getMessage(); String msg = authException.getMessage();
ServletUtils.renderString(response, JSON.toJSONString(R.failed(HttpStatus.FORBIDDEN, msg))); ServletUtils.renderString(response, JSON.toJSONString(R.fail(HttpStatus.FORBIDDEN, msg)));
} }
} }

View File

@@ -0,0 +1,117 @@
package com.ruoyi.common.security.handler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;
import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.exception.BaseException;
import com.ruoyi.common.core.exception.CustomException;
import com.ruoyi.common.core.exception.DemoModeException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
/**
* 全局异常处理器
*
* @author ruoyi
*/
@RestControllerAdvice
public class GlobalExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 基础异常
*/
@ExceptionHandler(BaseException.class)
public AjaxResult baseException(BaseException e)
{
return AjaxResult.error(e.getMessage());
}
/**
* 业务异常
*/
@ExceptionHandler(CustomException.class)
public AjaxResult businessException(CustomException e)
{
if (StringUtils.isNull(e.getCode()))
{
return AjaxResult.error(e.getMessage());
}
return AjaxResult.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(NoHandlerFoundException.class)
public AjaxResult handlerNoFoundException(Exception e)
{
log.error(e.getMessage(), e);
return AjaxResult.error(HttpStatus.NOT_FOUND, "路径不存在,请检查路径是否正确");
}
@ExceptionHandler(AccessDeniedException.class)
public AjaxResult handleAuthorizationException(AccessDeniedException e)
{
log.error(e.getMessage());
return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
}
@ExceptionHandler(AccountExpiredException.class)
public AjaxResult handleAccountExpiredException(AccountExpiredException e)
{
log.error(e.getMessage(), e);
return AjaxResult.error(e.getMessage());
}
@ExceptionHandler(UsernameNotFoundException.class)
public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e)
{
log.error(e.getMessage(), e);
return AjaxResult.error(e.getMessage());
}
@ExceptionHandler(Exception.class)
public AjaxResult handleException(Exception e)
{
log.error(e.getMessage(), e);
return AjaxResult.error(e.getMessage());
}
/**
* 自定义验证异常
*/
@ExceptionHandler(BindException.class)
public AjaxResult validatedBindException(BindException e)
{
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return AjaxResult.error(message);
}
/**
* 自定义验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object validExceptionHandler(MethodArgumentNotValidException e)
{
log.error(e.getMessage(), e);
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return AjaxResult.error(message);
}
/**
* 演示模式异常
*/
@ExceptionHandler(DemoModeException.class)
public AjaxResult demoModeException(DemoModeException e)
{
return AjaxResult.error("演示模式,不允许操作");
}
}

View File

@@ -155,7 +155,7 @@ public class PermissionService
/** /**
* 判断是否包含权限 * 判断是否包含权限
* *
* @param permissions 权限列表 * @param authorities 权限列表
* @param permission 权限字符串 * @param permission 权限字符串
* @return 用户是否具备某权限 * @return 用户是否具备某权限
*/ */

View File

@@ -1,5 +1,8 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.ruoyi.common.security.service.UserDetailsServiceImpl,\ com.ruoyi.common.security.service.UserDetailsServiceImpl,\
com.ruoyi.common.security.handler.CustomAccessDeniedHandler com.ruoyi.common.security.service.PermissionService,\
com.ruoyi.common.security.config.MethodSecurityConfig,\
com.ruoyi.common.security.handler.CustomAccessDeniedHandler,\
com.ruoyi.common.security.handler.GlobalExceptionHandler

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,9 @@ package com.ruoyi.common.swagger.config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties("swagger") @ConfigurationProperties("swagger")
public class SwaggerProperties public class SwaggerProperties
{ {

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -28,4 +28,4 @@ public class RuoYiGatewayApplication
" | | \\ / \\ / \n" + " | | \\ / \\ / \n" +
" ''-' `'-' `-..-' "); " ''-' `'-' `-..-' ");
} }
} }

View File

@@ -5,6 +5,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import com.google.code.kaptcha.impl.DefaultKaptcha; import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config; import com.google.code.kaptcha.util.Config;
import static com.google.code.kaptcha.Constants.*;
/** /**
* 验证码配置 * 验证码配置
@@ -14,42 +15,67 @@ import com.google.code.kaptcha.util.Config;
@Configuration @Configuration
public class CaptchaConfig public class CaptchaConfig
{ {
@Bean(name = "captchaProducer")
public DefaultKaptcha getKaptchaBean()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yesno
properties.setProperty(KAPTCHA_BORDER, "yes");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
// 验证码图片宽度 默认为200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 验证码图片高度 默认为50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 验证码文本字符大小 默认为40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
// 验证码文本字符长度 默认为5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
@Bean(name = "captchaProducerMath") @Bean(name = "captchaProducerMath")
public DefaultKaptcha getKaptchaBeanMath() public DefaultKaptcha getKaptchaBeanMath()
{ {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties(); Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yesno // 是否有边框 默认为true 我们可以自己设置yesno
properties.setProperty("kaptcha.border", "yes"); properties.setProperty(KAPTCHA_BORDER, "yes");
// 边框颜色 默认为Color.BLACK // 边框颜色 默认为Color.BLACK
properties.setProperty("kaptcha.border.color", "105,179,90"); properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
// 验证码文本字符颜色 默认为Color.BLACK // 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty("kaptcha.textproducer.font.color", "blue"); properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
// 验证码图片宽度 默认为200 // 验证码图片宽度 默认为200
properties.setProperty("kaptcha.image.width", "160"); properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 验证码图片高度 默认为50 // 验证码图片高度 默认为50
properties.setProperty("kaptcha.image.height", "60"); properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 验证码文本字符大小 默认为40 // 验证码文本字符大小 默认为40
properties.setProperty("kaptcha.textproducer.font.size", "35"); properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
// KAPTCHA_SESSION_KEY // KAPTCHA_SESSION_KEY
properties.setProperty("kaptcha.session.key", "kaptchaCodeMath"); properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
// 验证码文本生成器 // 验证码文本生成器
properties.setProperty("kaptcha.textproducer.impl", "com.ruoyi.gateway.config.KaptchaTextCreator"); properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.gateway.config.KaptchaTextCreator");
// 验证码文本字符间距 默认为2 // 验证码文本字符间距 默认为2
properties.setProperty("kaptcha.textproducer.char.space", "3"); properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
// 验证码文本字符长度 默认为5 // 验证码文本字符长度 默认为5
properties.setProperty("kaptcha.textproducer.char.length", "6"); properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
// fontSize) properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier");
// 验证码噪点颜色 默认为Color.BLACK // 验证码噪点颜色 默认为Color.BLACK
properties.setProperty("kaptcha.noise.color", "white"); properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
// 干扰实现类 // 干扰实现类
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise"); properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
// 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
// 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties); Config config = new Config(properties);
defaultKaptcha.setConfig(config); defaultKaptcha.setConfig(config);
return defaultKaptcha; return defaultKaptcha;

View File

@@ -0,0 +1,70 @@
package com.ruoyi.gateway.filter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.web.domain.AjaxResult;
import reactor.core.publisher.Mono;
/**
* 黑名单过滤器
*
* @author ruoyi
*/
@Component
public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config>
{
@Override
public GatewayFilter apply(Config config)
{
return (exchange, chain) -> {
String url = exchange.getRequest().getURI().getPath();
if (config.matchBlacklist(url))
{
ServerHttpResponse response = exchange.getResponse();
return exchange.getResponse().writeWith(
Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(AjaxResult.error("服务拒绝访问")))));
}
return chain.filter(exchange);
};
}
public BlackListUrlFilter()
{
super(Config.class);
}
public static class Config
{
private List<String> blacklistUrl;
private List<Pattern> blacklistUrlPattern = new ArrayList<>();
public boolean matchBlacklist(String url)
{
return blacklistUrlPattern.isEmpty() ? false : blacklistUrlPattern.stream().filter(p -> p.matcher(url).find()).findAny().isPresent();
}
public List<String> getBlacklistUrl()
{
return blacklistUrl;
}
public void setBlacklistUrl(List<String> blacklistUrl)
{
this.blacklistUrl = blacklistUrl;
this.blacklistUrlPattern.clear();
this.blacklistUrl.forEach(url -> {
this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE));
});
}
}
}

View File

@@ -31,6 +31,10 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
private static final String CODE = "code"; private static final String CODE = "code";
private static final String UUID = "uuid"; private static final String UUID = "uuid";
private static final String GRANT_TYPE = "grant_type";
private static final String REFRESH_TOKEN = "refresh_token";
@Override @Override
public GatewayFilter apply(Object config) public GatewayFilter apply(Object config)
@@ -43,6 +47,13 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
{ {
return chain.filter(exchange); return chain.filter(exchange);
} }
// 刷新token请求不处理
String grantType = request.getQueryParams().getFirst(GRANT_TYPE);
if (StringUtils.containsIgnoreCase(request.getURI().getPath(), AUTH_URL) && StringUtils.containsIgnoreCase(grantType, REFRESH_TOKEN))
{
return chain.filter(exchange);
}
// 消息头存在内容,且不存在验证码参数,不处理 // 消息头存在内容,且不存在验证码参数,不处理
String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION); String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
@@ -59,6 +70,7 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
catch (Exception e) catch (Exception e)
{ {
ServerHttpResponse response = exchange.getResponse(); ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return exchange.getResponse().writeWith( return exchange.getResponse().writeWith(
Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(AjaxResult.error(e.getMessage()))))); Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(AjaxResult.error(e.getMessage())))));
} }

View File

@@ -0,0 +1,66 @@
package com.ruoyi.gateway.handler;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.domain.R;
import reactor.core.publisher.Mono;
/**
* 网关统一异常处理
*
* @author ruoyi
*/
@Order(-1)
@Configuration
public class GatewayExceptionHandler implements ErrorWebExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
{
ServerHttpResponse response = exchange.getResponse();
if (exchange.getResponse().isCommitted())
{
return Mono.error(ex);
}
String msg;
if (ex instanceof NotFoundException)
{
msg = "服务未找到";
}
else if (ex instanceof ResponseStatusException)
{
ResponseStatusException responseStatusException = (ResponseStatusException) ex;
msg = responseStatusException.getMessage();
}
else
{
msg = "内部服务器错误";
}
log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
response.setStatusCode(HttpStatus.OK);
return response.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg)));
}));
}
}

View File

@@ -3,6 +3,7 @@ package com.ruoyi.gateway.service.impl;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -25,28 +26,46 @@ import com.ruoyi.gateway.service.ValidateCodeService;
@Service @Service
public class ValidateCodeServiceImpl implements ValidateCodeService public class ValidateCodeServiceImpl implements ValidateCodeService
{ {
@Autowired @Resource(name = "captchaProducer")
private Producer producer; private Producer captchaProducer;
@Resource(name = "captchaProducerMath")
private Producer captchaProducerMath;
@Autowired @Autowired
private RedisService redisService; private RedisService redisService;
// 验证码类型
private String captchaType = "math";
/** /**
* 生成验证码 * 生成验证码
*/ */
@Override @Override
public AjaxResult createCapcha() throws IOException, CaptchaException public AjaxResult createCapcha() throws IOException, CaptchaException
{ {
// 生成验证码
String capText = producer.createText();
String capStr = capText.substring(0, capText.lastIndexOf("@"));
String verifyCode = capText.substring(capText.lastIndexOf("@") + 1);
BufferedImage image = producer.createImage(capStr);
// 保存验证码信息 // 保存验证码信息
String uuid = IdUtils.simpleUUID(); String uuid = IdUtils.simpleUUID();
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
redisService.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); String capStr = null, code = null;
BufferedImage image = null;
// 生成验证码
if ("math".equals(captchaType))
{
String capText = captchaProducerMath.createText();
capStr = capText.substring(0, capText.lastIndexOf("@"));
code = capText.substring(capText.lastIndexOf("@") + 1);
image = captchaProducerMath.createImage(capStr);
}
else if ("char".equals(captchaType))
{
capStr = code = captchaProducer.createText();
image = captchaProducer.createImage(capStr);
}
redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
// 转换流信息写出 // 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream(); FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try try

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -148,15 +148,27 @@ public class GenController extends BaseController
} }
/** /**
* 生成代码 * 生成代码(下载方式)
*/
@PreAuthorize("@ss.hasPermi('tool:gen:code')")
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
@GetMapping("/download/{tableName}")
public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
{
byte[] data = genTableService.downloadCode(tableName);
genCode(response, data);
}
/**
* 生成代码(自定义路径)
*/ */
@PreAuthorize("@ss.hasPermi('tool:gen:code')") @PreAuthorize("@ss.hasPermi('tool:gen:code')")
@Log(title = "代码生成", businessType = BusinessType.GENCODE) @Log(title = "代码生成", businessType = BusinessType.GENCODE)
@GetMapping("/genCode/{tableName}") @GetMapping("/genCode/{tableName}")
public void genCode(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException public AjaxResult genCode(HttpServletResponse response, @PathVariable("tableName") String tableName)
{ {
byte[] data = genTableService.generatorCode(tableName); genTableService.generatorCode(tableName);
genCode(response, data); return AjaxResult.success();
} }
/** /**
@@ -168,7 +180,7 @@ public class GenController extends BaseController
public void batchGenCode(HttpServletResponse response, String tables) throws IOException public void batchGenCode(HttpServletResponse response, String tables) throws IOException
{ {
String[] tableNames = Convert.toStrArray(tables); String[] tableNames = Convert.toStrArray(tables);
byte[] data = genTableService.generatorCode(tableNames); byte[] data = genTableService.downloadCode(tableNames);
genCode(response, data); genCode(response, data);
} }
@@ -183,4 +195,4 @@ public class GenController extends BaseController
response.setContentType("application/octet-stream; charset=UTF-8"); response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(data, response.getOutputStream()); IOUtils.write(data, response.getOutputStream());
} }
} }

View File

@@ -55,6 +55,12 @@ public class GenTable extends BaseEntity
@NotBlank(message = "作者不能为空") @NotBlank(message = "作者不能为空")
private String functionAuthor; private String functionAuthor;
/** 生成代码方式0zip压缩包 1自定义路径 */
private String genType;
/** 生成路径(不填默认项目路径) */
private String genPath;
/** 主键信息 */ /** 主键信息 */
private GenTableColumn pkColumn; private GenTableColumn pkColumn;
@@ -74,6 +80,12 @@ public class GenTable extends BaseEntity
/** 树名称字段 */ /** 树名称字段 */
private String treeName; private String treeName;
/** 上级菜单ID字段 */
private String parentMenuId;
/** 上级菜单名称字段 */
private String parentMenuName;
public Long getTableId() public Long getTableId()
{ {
return tableId; return tableId;
@@ -174,6 +186,26 @@ public class GenTable extends BaseEntity
this.functionAuthor = functionAuthor; this.functionAuthor = functionAuthor;
} }
public String getGenType()
{
return genType;
}
public void setGenType(String genType)
{
this.genType = genType;
}
public String getGenPath()
{
return genPath;
}
public void setGenPath(String genPath)
{
this.genPath = genPath;
}
public GenTableColumn getPkColumn() public GenTableColumn getPkColumn()
{ {
return pkColumn; return pkColumn;
@@ -234,6 +266,26 @@ public class GenTable extends BaseEntity
this.treeName = treeName; this.treeName = treeName;
} }
public String getParentMenuId()
{
return parentMenuId;
}
public void setParentMenuId(String parentMenuId)
{
this.parentMenuId = parentMenuId;
}
public String getParentMenuName()
{
return parentMenuName;
}
public void setParentMenuName(String parentMenuName)
{
this.parentMenuName = parentMenuName;
}
public boolean isTree() public boolean isTree()
{ {
return isTree(this.tplCategory); return isTree(this.tplCategory);
@@ -268,4 +320,4 @@ public class GenTable extends BaseEntity
} }
return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
} }
} }

View File

@@ -21,7 +21,7 @@ public class GenTableColumnServiceImpl implements IGenTableColumnService
/** /**
* 查询业务字段列表 * 查询业务字段列表
* *
* @param genTableColumn 业务字段编号 * @param tableId 业务字段编号
* @return 业务字段集合 * @return 业务字段集合
*/ */
@Override @Override

View File

@@ -1,6 +1,7 @@
package com.ruoyi.gen.service; package com.ruoyi.gen.service;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -22,7 +23,10 @@ import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.constant.GenConstants; import com.ruoyi.common.core.constant.GenConstants;
import com.ruoyi.common.core.exception.CustomException; import com.ruoyi.common.core.exception.CustomException;
import com.ruoyi.common.core.text.CharsetKit;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileUtils;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.gen.domain.GenTable; import com.ruoyi.gen.domain.GenTable;
import com.ruoyi.gen.domain.GenTableColumn; import com.ruoyi.gen.domain.GenTableColumn;
import com.ruoyi.gen.mapper.GenTableColumnMapper; import com.ruoyi.gen.mapper.GenTableColumnMapper;
@@ -79,6 +83,7 @@ public class GenTableServiceImpl implements IGenTableService
* @param genTable 业务信息 * @param genTable 业务信息
* @return 数据库表集合 * @return 数据库表集合
*/ */
@Override
public List<GenTable> selectDbTableList(GenTable genTable) public List<GenTable> selectDbTableList(GenTable genTable)
{ {
return genTableMapper.selectDbTableList(genTable); return genTableMapper.selectDbTableList(genTable);
@@ -90,6 +95,7 @@ public class GenTableServiceImpl implements IGenTableService
* @param tableNames 表名称组 * @param tableNames 表名称组
* @return 数据库表集合 * @return 数据库表集合
*/ */
@Override
public List<GenTable> selectDbTableListByNames(String[] tableNames) public List<GenTable> selectDbTableListByNames(String[] tableNames)
{ {
return genTableMapper.selectDbTableListByNames(tableNames); return genTableMapper.selectDbTableListByNames(tableNames);
@@ -120,7 +126,7 @@ public class GenTableServiceImpl implements IGenTableService
/** /**
* 删除业务对象 * 删除业务对象
* *
* @param ids 需要删除的数据ID * @param tableIds 需要删除的数据ID
* @return 结果 * @return 结果
*/ */
@Override @Override
@@ -140,10 +146,10 @@ public class GenTableServiceImpl implements IGenTableService
@Transactional @Transactional
public void importGenTable(List<GenTable> tableList) public void importGenTable(List<GenTable> tableList)
{ {
String operName = ""; String operName = SecurityUtils.getUsername();
for (GenTable table : tableList) try
{ {
try for (GenTable table : tableList)
{ {
String tableName = table.getTableName(); String tableName = table.getTableName();
GenUtils.initTable(table, operName); GenUtils.initTable(table, operName);
@@ -159,10 +165,10 @@ public class GenTableServiceImpl implements IGenTableService
} }
} }
} }
catch (Exception e) }
{ catch (Exception e)
log.error("表名 " + table.getTableName() + " 导入失败:", e); {
} throw new CustomException("导入失败:" + e.getMessage());
} }
} }
@@ -198,13 +204,13 @@ public class GenTableServiceImpl implements IGenTableService
} }
/** /**
* 生成代码 * 生成代码(下载方式)
* *
* @param tableName 表名称 * @param tableName 表名称
* @return 数据 * @return 数据
*/ */
@Override @Override
public byte[] generatorCode(String tableName) public byte[] downloadCode(String tableName)
{ {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream); ZipOutputStream zip = new ZipOutputStream(outputStream);
@@ -214,13 +220,55 @@ public class GenTableServiceImpl implements IGenTableService
} }
/** /**
* 批量生成代码 * 生成代码(自定义路径)
*
* @param tableName 表名称
* @return 数据
*/
@Override
public void generatorCode(String tableName)
{
// 查询表信息
GenTable table = genTableMapper.selectGenTableByName(tableName);
// 查询列信息
List<GenTableColumn> columns = table.getColumns();
setPkColumn(table, columns);
VelocityInitializer.initVelocity();
VelocityContext context = VelocityUtils.prepareContext(table);
// 获取模板列表
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
for (String template : templates)
{
if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
{
// 渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
tpl.merge(context, sw);
try
{
String path = getGenPath(table, template);
FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
}
catch (IOException e)
{
throw new CustomException("渲染模板失败,表名:" + table.getTableName());
}
}
}
}
/**
* 批量生成代码(下载方式)
* *
* @param tableNames 表数组 * @param tableNames 表数组
* @return 数据 * @return 数据
*/ */
@Override @Override
public byte[] generatorCode(String[] tableNames) public byte[] downloadCode(String[] tableNames)
{ {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream); ZipOutputStream zip = new ZipOutputStream(outputStream);
@@ -276,6 +324,7 @@ public class GenTableServiceImpl implements IGenTableService
* *
* @param genTable 业务信息 * @param genTable 业务信息
*/ */
@Override
public void validateEdit(GenTable genTable) public void validateEdit(GenTable genTable)
{ {
if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) if (GenConstants.TPL_TREE.equals(genTable.getTplCategory()))
@@ -300,7 +349,7 @@ public class GenTableServiceImpl implements IGenTableService
/** /**
* 设置主键列信息 * 设置主键列信息
* *
* @param genTable 业务表信息 * @param table 业务表信息
* @param columns 业务字段列表 * @param columns 业务字段列表
*/ */
public void setPkColumn(GenTable table, List<GenTableColumn> columns) public void setPkColumn(GenTable table, List<GenTableColumn> columns)
@@ -332,9 +381,31 @@ public class GenTableServiceImpl implements IGenTableService
String treeCode = paramsObj.getString(GenConstants.TREE_CODE); String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE); String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
String treeName = paramsObj.getString(GenConstants.TREE_NAME); String treeName = paramsObj.getString(GenConstants.TREE_NAME);
String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID);
String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
genTable.setTreeCode(treeCode); genTable.setTreeCode(treeCode);
genTable.setTreeParentCode(treeParentCode); genTable.setTreeParentCode(treeParentCode);
genTable.setTreeName(treeName); genTable.setTreeName(treeName);
genTable.setParentMenuId(parentMenuId);
genTable.setParentMenuName(parentMenuName);
} }
} }
}
/**
* 获取代码生成地址
*
* @param table 业务表信息
* @param template 模板文件路径
* @return 生成地址
*/
public static String getGenPath(GenTable table, String template)
{
String genPath = table.getGenPath();
if (StringUtils.equals(genPath, "/"))
{
return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
}
return genPath + File.separator + VelocityUtils.getFileName(template, table);
}
}

View File

@@ -13,7 +13,7 @@ public interface IGenTableColumnService
/** /**
* 查询业务字段列表 * 查询业务字段列表
* *
* @param genTableColumn 业务字段编号 * @param tableId 业务字段编号
* @return 业务字段集合 * @return 业务字段集合
*/ */
public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId); public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);

View File

@@ -75,20 +75,28 @@ public interface IGenTableService
public Map<String, String> previewCode(Long tableId); public Map<String, String> previewCode(Long tableId);
/** /**
* 生成代码 * 生成代码(下载方式)
* *
* @param tableName 表名称 * @param tableName 表名称
* @return 数据 * @return 数据
*/ */
public byte[] generatorCode(String tableName); public byte[] downloadCode(String tableName);
/** /**
* 批量生成代码 * 生成代码(自定义路径)
*
* @param tableName 表名称
* @return 数据
*/
public void generatorCode(String tableName);
/**
* 批量生成代码(下载方式)
* *
* @param tableNames 表数组 * @param tableNames 表数组
* @return 数据 * @return 数据
*/ */
public byte[] generatorCode(String[] tableNames); public byte[] downloadCode(String[] tableNames);
/** /**
* 修改保存参数校验 * 修改保存参数校验

View File

@@ -62,7 +62,7 @@ public class GenUtils
String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ","); String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)
{ {
column.setJavaType(GenConstants.TYPE_DOUBLE); column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
} }
// 如果是整形 // 如果是整形
else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10)
@@ -195,7 +195,7 @@ public class GenUtils
/** /**
* 关键字替换 * 关键字替换
* *
* @param name 需要被替换的名字 * @param text 需要被替换的名字
* @return 替换后的名字 * @return 替换后的名字
*/ */
public static String replaceText(String text) public static String replaceText(String text)

View File

@@ -23,6 +23,9 @@ public class VelocityUtils
/** mybatis空间路径 */ /** mybatis空间路径 */
private static final String MYBATIS_PATH = "main/resources/mapper"; private static final String MYBATIS_PATH = "main/resources/mapper";
/** 默认上级菜单,系统工具 */
private static final String DEFAULT_PARENT_MENU_ID = "3";
/** /**
* 设置模板变量信息 * 设置模板变量信息
@@ -55,12 +58,21 @@ public class VelocityUtils
velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
velocityContext.put("columns", genTable.getColumns()); velocityContext.put("columns", genTable.getColumns());
velocityContext.put("table", genTable); velocityContext.put("table", genTable);
setMenuVelocityContext(velocityContext, genTable);
if (GenConstants.TPL_TREE.equals(tplCategory)) if (GenConstants.TPL_TREE.equals(tplCategory))
{ {
setTreeVelocityContext(velocityContext, genTable); setTreeVelocityContext(velocityContext, genTable);
} }
return velocityContext; return velocityContext;
} }
public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)
{
String options = genTable.getOptions();
JSONObject paramsObj = JSONObject.parseObject(options);
String parentMenuId = getParentMenuId(paramsObj);
context.put("parentMenuId", parentMenuId);
}
public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) public static void setTreeVelocityContext(VelocityContext context, GenTable genTable)
{ {
@@ -190,7 +202,7 @@ public class VelocityUtils
/** /**
* 根据列类型获取导入包 * 根据列类型获取导入包
* *
* @param column 列集合 * @param columns 列集合
* @return 返回需要导入的包列表 * @return 返回需要导入的包列表
*/ */
public static HashSet<String> getImportList(List<GenTableColumn> columns) public static HashSet<String> getImportList(List<GenTableColumn> columns)
@@ -221,13 +233,27 @@ public class VelocityUtils
public static String getPermissionPrefix(String moduleName, String businessName) public static String getPermissionPrefix(String moduleName, String businessName)
{ {
return StringUtils.format("{}:{}", moduleName, businessName); return StringUtils.format("{}:{}", moduleName, businessName);
}
/**
* 获取上级菜单ID字段
*
* @param paramsObj 生成其他选项
* @return 上级菜单ID字段
*/
public static String getParentMenuId(JSONObject paramsObj)
{
if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID))
{
return paramsObj.getString(GenConstants.PARENT_MENU_ID);
}
return DEFAULT_PARENT_MENU_ID;
} }
/** /**
* 获取树编码 * 获取树编码
* *
* @param options 生成其他选项 * @param paramsObj 生成其他选项
* @return 树编码 * @return 树编码
*/ */
public static String getTreecode(JSONObject paramsObj) public static String getTreecode(JSONObject paramsObj)
@@ -236,13 +262,13 @@ public class VelocityUtils
{ {
return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE)); return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE));
} }
return ""; return StringUtils.EMPTY;
} }
/** /**
* 获取树父编码 * 获取树父编码
* *
* @param options 生成其他选项 * @param paramsObj 生成其他选项
* @return 树父编码 * @return 树父编码
*/ */
public static String getTreeParentCode(JSONObject paramsObj) public static String getTreeParentCode(JSONObject paramsObj)
@@ -251,13 +277,13 @@ public class VelocityUtils
{ {
return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE)); return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE));
} }
return ""; return StringUtils.EMPTY;
} }
/** /**
* 获取树名称 * 获取树名称
* *
* @param options 生成其他选项 * @param paramsObj 生成其他选项
* @return 树名称 * @return 树名称
*/ */
public static String getTreeName(JSONObject paramsObj) public static String getTreeName(JSONObject paramsObj)
@@ -266,7 +292,7 @@ public class VelocityUtils
{ {
return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME)); return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME));
} }
return ""; return StringUtils.EMPTY;
} }
/** /**
@@ -295,4 +321,4 @@ public class VelocityUtils
} }
return num; return num;
} }
} }

View File

@@ -15,6 +15,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="businessName" column="business_name" /> <result property="businessName" column="business_name" />
<result property="functionName" column="function_name" /> <result property="functionName" column="function_name" />
<result property="functionAuthor" column="function_author" /> <result property="functionAuthor" column="function_author" />
<result property="genType" column="gen_type" />
<result property="genPath" column="gen_path" />
<result property="options" column="options" /> <result property="options" column="options" />
<result property="createBy" column="create_by" /> <result property="createBy" column="create_by" />
<result property="createTime" column="create_time" /> <result property="createTime" column="create_time" />
@@ -50,7 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectGenTableVo"> <sql id="selectGenTableVo">
select table_id, table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, options, create_by, create_time, update_by, update_time, remark from gen_table select table_id, table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
</sql> </sql>
<select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult"> <select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
@@ -62,6 +64,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="tableComment != null and tableComment != ''"> <if test="tableComment != null and tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
</if> </if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
</if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
</if>
</where> </where>
</select> </select>
@@ -94,7 +102,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult"> <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark, SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@@ -102,7 +110,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult"> <select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark, SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@@ -120,6 +128,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="businessName != null and businessName != ''">business_name,</if> <if test="businessName != null and businessName != ''">business_name,</if>
<if test="functionName != null and functionName != ''">function_name,</if> <if test="functionName != null and functionName != ''">function_name,</if>
<if test="functionAuthor != null and functionAuthor != ''">function_author,</if> <if test="functionAuthor != null and functionAuthor != ''">function_author,</if>
<if test="genType != null and genType != ''">gen_type,</if>
<if test="genPath != null and genPath != ''">gen_path,</if>
<if test="remark != null and remark != ''">remark,</if> <if test="remark != null and remark != ''">remark,</if>
<if test="createBy != null and createBy != ''">create_by,</if> <if test="createBy != null and createBy != ''">create_by,</if>
create_time create_time
@@ -133,6 +143,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="businessName != null and businessName != ''">#{businessName},</if> <if test="businessName != null and businessName != ''">#{businessName},</if>
<if test="functionName != null and functionName != ''">#{functionName},</if> <if test="functionName != null and functionName != ''">#{functionName},</if>
<if test="functionAuthor != null and functionAuthor != ''">#{functionAuthor},</if> <if test="functionAuthor != null and functionAuthor != ''">#{functionAuthor},</if>
<if test="genType != null and genType != ''">#{genType},</if>
<if test="genPath != null and genPath != ''">#{genPath},</if>
<if test="remark != null and remark != ''">#{remark},</if> <if test="remark != null and remark != ''">#{remark},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if> <if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate() sysdate()
@@ -146,6 +158,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if> <if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if>
<if test="className != null and className != ''">class_name = #{className},</if> <if test="className != null and className != ''">class_name = #{className},</if>
<if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if> <if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if>
<if test="genType != null and genType != ''">gen_type = #{genType},</if>
<if test="genPath != null and genPath != ''">gen_path = #{genPath},</if>
<if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if> <if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if>
<if test="packageName != null and packageName != ''">package_name = #{packageName},</if> <if test="packageName != null and packageName != ''">package_name = #{packageName},</if>
<if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if> <if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if>

View File

@@ -63,12 +63,12 @@ public class ${ClassName}Controller extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')")
@Log(title = "${functionName}", businessType = BusinessType.EXPORT) @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
@GetMapping("/export") @PostMapping("/export")
public void export(HttpServletResponse response, ${ClassName} ${className}) throws IOException public void export(HttpServletResponse response, ${ClassName} ${className}) throws IOException
{ {
List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
return util.exportExcel(response, list, "${businessName}"); util.exportExcel(response, list, "${businessName}");
} }
/** /**

View File

@@ -5,11 +5,11 @@ import ${import};
#end #end
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.framework.aspectj.lang.annotation.Excel; import com.ruoyi.common.core.annotation.Excel;
#if($table.crud) #if($table.crud)
import com.ruoyi.framework.web.domain.BaseEntity; import com.ruoyi.common.core.web.domain.BaseEntity;
#elseif($table.tree) #elseif($table.tree)
import com.ruoyi.framework.web.domain.TreeEntity; import com.ruoyi.common.core.web.domain.TreeEntity;
#end #end
/** /**

View File

@@ -3,7 +3,7 @@ package ${packageName}.service.impl;
import java.util.List; import java.util.List;
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.javaField == 'createTime' || $column.javaField == 'updateTime') #if($column.javaField == 'createTime' || $column.javaField == 'updateTime')
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.core.utils.DateUtils;
#break #break
#end #end
#end #end

View File

@@ -1,6 +1,6 @@
-- 菜单 SQL -- 菜单 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}', '3', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '${functionName}菜单'); values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '${functionName}菜单');
-- 按钮父菜单ID -- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID(); SELECT @parentId := LAST_INSERT_ID();

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns) #foreach($column in $columns)
#if($column.query) #if($column.query)
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
@@ -51,23 +51,30 @@
#end #end
#end #end
<el-form-item> <el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button <el-button
class="filter-item"
type="primary"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索</el-button>
<el-button
class="filter-item"
type="primary" type="primary"
icon="el-icon-plus" icon="el-icon-plus"
size="mini" size="mini"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
</el-form-item> </el-col>
</el-form> <div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table <el-table
v-loading="loading" v-loading="loading"
@@ -157,6 +164,23 @@
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}">
<el-checkbox-group v-model="form.${field}">
<el-checkbox
v-for="dict in ${field}Options"
:key="dict.dictValue"
:label="dict.dictValue">
{{dict.dictLabel}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}">
<el-checkbox-group v-model="form.${field}">
<el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType) #elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
@@ -212,6 +236,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 显示搜索条件
showSearch: true,
// ${functionName}表格数据 // ${functionName}表格数据
${businessName}List: [], ${businessName}List: [],
// ${functionName}树选项 // ${functionName}树选项
@@ -236,7 +262,7 @@ export default {
queryParams: { queryParams: {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.query) #if($column.query)
$column.javaField: undefined#if($velocityCount != $columns.size()),#end $column.javaField: null#if($velocityCount != $columns.size()),#end
#end #end
#end #end
@@ -312,7 +338,7 @@ export default {
#end #end
// $comment字典翻译 // $comment字典翻译
${column.javaField}Format(row, column) { ${column.javaField}Format(row, column) {
return this.selectDictLabel(this.${column.javaField}Options, row.${column.javaField}); return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(this.${column.javaField}Options, row.${column.javaField});
}, },
#end #end
#end #end
@@ -326,10 +352,13 @@ export default {
this.form = { this.form = {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "radio") #if($column.htmlType == "radio")
$column.javaField: "0"#if($velocityCount != $columns.size()),#end $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($velocityCount != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
$column.javaField: []#if($velocityCount != $columns.size()),#end
#else #else
$column.javaField: undefined#if($velocityCount != $columns.size()),#end $column.javaField: null#if($velocityCount != $columns.size()),#end
#end #end
#end #end
@@ -356,20 +385,30 @@ export default {
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
this.getTreeselect(); this.getTreeselect();
if (row != undefined) { if (row != null) {
this.form.${treeParentCode} = row.${treeCode}; this.form.${treeParentCode} = row.${treeCode};
} }
get${BusinessName}(row.${pkColumn.javaField}).then(response => { get${BusinessName}(row.${pkColumn.javaField}).then(response => {
this.form = response.data; this.form = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(",");
#end
#end
this.open = true; this.open = true;
this.title = "修改${functionName}"; this.title = "修改${functionName}";
}); });
}, },
/** 提交按钮 */ /** 提交按钮 */
submitForm: function() { submitForm() {
this.#[[$]]#refs["form"].validate(valid => { this.#[[$]]#refs["form"].validate(valid => {
if (valid) { if (valid) {
if (this.form.${pkColumn.javaField} != undefined) { #foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(",");
#end
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => { update${BusinessName}(this.form).then(response => {
if (response.code === 200) { if (response.code === 200) {
this.msgSuccess("修改成功"); this.msgSuccess("修改成功");
@@ -404,4 +443,4 @@ export default {
} }
} }
}; };
</script> </script>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns) #foreach($column in $columns)
#if($column.query) #if($column.query)
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
@@ -51,7 +51,7 @@
#end #end
#end #end
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -95,6 +95,14 @@
v-hasPermi="['${moduleName}:${businessName}:export']" v-hasPermi="['${moduleName}:${businessName}:export']"
>导出</el-button> >导出</el-button>
</el-col> </el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row> </el-row>
<el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
@@ -185,6 +193,23 @@
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}">
<el-checkbox-group v-model="form.${field}">
<el-checkbox
v-for="dict in ${field}Options"
:key="dict.dictValue"
:label="dict.dictValue">
{{dict.dictLabel}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}">
<el-checkbox-group v-model="form.${field}">
<el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType) #elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<el-radio-group v-model="form.${field}"> <el-radio-group v-model="form.${field}">
@@ -243,6 +268,8 @@ export default {
single: true, single: true,
// 非多个禁用 // 非多个禁用
multiple: true, multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数 // 总条数
total: 0, total: 0,
// ${functionName}表格数据 // ${functionName}表格数据
@@ -269,7 +296,7 @@ export default {
pageSize: 10, pageSize: 10,
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.query) #if($column.query)
$column.javaField: undefined#if($velocityCount != $columns.size()),#end $column.javaField: null#if($velocityCount != $columns.size()),#end
#end #end
#end #end
@@ -326,7 +353,7 @@ export default {
#end #end
// $comment字典翻译 // $comment字典翻译
${column.javaField}Format(row, column) { ${column.javaField}Format(row, column) {
return this.selectDictLabel(this.${column.javaField}Options, row.${column.javaField}); return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(this.${column.javaField}Options, row.${column.javaField});
}, },
#end #end
#end #end
@@ -340,10 +367,13 @@ export default {
this.form = { this.form = {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "radio") #if($column.htmlType == "radio")
$column.javaField: "0"#if($velocityCount != $columns.size()),#end $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($velocityCount != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
$column.javaField: []#if($velocityCount != $columns.size()),#end
#else #else
$column.javaField: undefined#if($velocityCount != $columns.size()),#end $column.javaField: null#if($velocityCount != $columns.size()),#end
#end #end
#end #end
@@ -363,7 +393,7 @@ export default {
// 多选框选中数据 // 多选框选中数据
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.ids = selection.map(item => item.${pkColumn.javaField}) this.ids = selection.map(item => item.${pkColumn.javaField})
this.single = selection.length!=1 this.single = selection.length!==1
this.multiple = !selection.length this.multiple = !selection.length
}, },
/** 新增按钮操作 */ /** 新增按钮操作 */
@@ -378,15 +408,25 @@ export default {
const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
get${BusinessName}(${pkColumn.javaField}).then(response => { get${BusinessName}(${pkColumn.javaField}).then(response => {
this.form = response.data; this.form = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(",");
#end
#end
this.open = true; this.open = true;
this.title = "修改${functionName}"; this.title = "修改${functionName}";
}); });
}, },
/** 提交按钮 */ /** 提交按钮 */
submitForm: function() { submitForm() {
this.#[[$]]#refs["form"].validate(valid => { this.#[[$]]#refs["form"].validate(valid => {
if (valid) { if (valid) {
if (this.form.${pkColumn.javaField} != undefined) { #foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(",");
#end
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => { update${BusinessName}(this.form).then(response => {
if (response.code === 200) { if (response.code === 200) {
this.msgSuccess("修改成功"); this.msgSuccess("修改成功");

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -21,8 +21,10 @@ import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo; import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.job.domain.SysJob; import com.ruoyi.job.domain.SysJob;
import com.ruoyi.job.service.ISysJobService; import com.ruoyi.job.service.ISysJobService;
import com.ruoyi.job.util.CronUtils;
/** /**
* 调度任务信息操作处理 * 调度任务信息操作处理
@@ -79,6 +81,11 @@ public class SysJobController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@RequestBody SysJob sysJob) throws SchedulerException, TaskException public AjaxResult add(@RequestBody SysJob sysJob) throws SchedulerException, TaskException
{ {
if (!CronUtils.isValid(sysJob.getCronExpression()))
{
return AjaxResult.error("cron表达式不正确");
}
sysJob.setCreateBy(SecurityUtils.getUsername());
return toAjax(jobService.insertJob(sysJob)); return toAjax(jobService.insertJob(sysJob));
} }
@@ -90,6 +97,11 @@ public class SysJobController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@RequestBody SysJob sysJob) throws SchedulerException, TaskException public AjaxResult edit(@RequestBody SysJob sysJob) throws SchedulerException, TaskException
{ {
if (!CronUtils.isValid(sysJob.getCronExpression()))
{
return AjaxResult.error("cron表达式不正确");
}
sysJob.setUpdateBy(SecurityUtils.getUsername());
return toAjax(jobService.updateJob(sysJob)); return toAjax(jobService.updateJob(sysJob));
} }

View File

@@ -65,7 +65,7 @@ public abstract class AbstractQuartzJob implements Job
* 执行后 * 执行后
* *
* @param context 工作执行上下文对象 * @param context 工作执行上下文对象
* @param sysScheduleJob 系统计划任务 * @param sysJob 系统计划任务
*/ */
protected void after(JobExecutionContext context, SysJob sysJob, Exception e) protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
{ {

View File

@@ -65,7 +65,7 @@ public class JobInvokeUtil
/** /**
* 校验是否为为class包名 * 校验是否为为class包名
* *
* @param str 名称 * @param invokeTarget 名称
* @return true是 false否 * @return true是 false否
*/ */
public static boolean isValidClassName(String invokeTarget) public static boolean isValidClassName(String invokeTarget)

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>2.0.0</version> <version>2.1.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -17,6 +17,7 @@ import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo; import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.domain.SysClientDetails; import com.ruoyi.system.domain.SysClientDetails;
import com.ruoyi.system.service.ISysClientDetailsService; import com.ruoyi.system.service.ISysClientDetailsService;
@@ -67,6 +68,7 @@ public class SysClientDetailsController extends BaseController
{ {
return AjaxResult.error("新增终端'" + clientId + "'失败,编号已存在"); return AjaxResult.error("新增终端'" + clientId + "'失败,编号已存在");
} }
sysClientDetails.setClientSecret(SecurityUtils.encryptPassword(sysClientDetails.getClientSecret()));
return toAjax(sysClientDetailsService.insertSysClientDetails(sysClientDetails)); return toAjax(sysClientDetailsService.insertSysClientDetails(sysClientDetails));
} }
@@ -78,6 +80,7 @@ public class SysClientDetailsController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@RequestBody SysClientDetails sysClientDetails) public AjaxResult edit(@RequestBody SysClientDetails sysClientDetails)
{ {
sysClientDetails.setClientSecret(SecurityUtils.encryptPassword(sysClientDetails.getClientSecret()));
return toAjax(sysClientDetailsService.updateSysClientDetails(sysClientDetails)); return toAjax(sysClientDetailsService.updateSysClientDetails(sysClientDetails));
} }

View File

@@ -62,7 +62,6 @@ public class SysConfigController extends BaseController
/** /**
* 根据参数编号获取详细信息 * 根据参数编号获取详细信息
*/ */
@PreAuthorize("@ss.hasRole('admin')")
@GetMapping(value = "/{configId}") @GetMapping(value = "/{configId}")
public AjaxResult getInfo(@PathVariable Long configId) public AjaxResult getInfo(@PathVariable Long configId)
{ {

View File

@@ -3,6 +3,7 @@ package com.ruoyi.system.controller;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
@@ -26,6 +27,7 @@ import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.domain.SysRole;
import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.model.UserInfo; import com.ruoyi.system.api.model.UserInfo;
import com.ruoyi.system.service.ISysPermissionService; import com.ruoyi.system.service.ISysPermissionService;
@@ -102,6 +104,10 @@ public class SysUserController extends BaseController
public R<UserInfo> info(@PathVariable("username") String username) public R<UserInfo> info(@PathVariable("username") String username)
{ {
SysUser sysUser = userService.selectUserByUserName(username); SysUser sysUser = userService.selectUserByUserName(username);
if (StringUtils.isNull(sysUser))
{
return R.fail("用户名或密码错误");
}
// 角色集合 // 角色集合
Set<String> roles = permissionService.getRolePermission(sysUser.getUserId()); Set<String> roles = permissionService.getRolePermission(sysUser.getUserId());
// 权限集合 // 权限集合
@@ -141,7 +147,8 @@ public class SysUserController extends BaseController
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{ {
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
ajax.put("roles", roleService.selectRoleAll()); List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll()); ajax.put("posts", postService.selectPostAll());
if (StringUtils.isNotNull(userId)) if (StringUtils.isNotNull(userId))
{ {

View File

@@ -49,12 +49,4 @@ public interface ISysClientDetailsService
* @return 结果 * @return 结果
*/ */
public int deleteSysClientDetailsByIds(String[] clientIds); public int deleteSysClientDetailsByIds(String[] clientIds);
/**
* 删除终端配置信息
*
* @param clientId 终端配置ID
* @return 结果
*/
public int deleteSysClientDetailsById(String clientId);
} }

View File

@@ -7,7 +7,7 @@ public interface ISysPermissionService
/** /**
* 获取角色数据权限 * 获取角色数据权限
* *
* @param user 用户信息 * @param userId 用户Id
* @return 角色权限信息 * @return 角色权限信息
*/ */
public Set<String> getRolePermission(Long userId); public Set<String> getRolePermission(Long userId);
@@ -15,7 +15,7 @@ public interface ISysPermissionService
/** /**
* 获取菜单数据权限 * 获取菜单数据权限
* *
* @param user 用户信息 * @param userId 用户Id
* @return 菜单权限信息 * @return 菜单权限信息
*/ */
public Set<String> getMenuPermission(Long userId); public Set<String> getMenuPermission(Long userId);

View File

@@ -1,47 +0,0 @@
//package com.ruoyi.system.service;
//
//import com.ruoyi.system.domain.SysUserOnline;
//
///**
// * 在线用户 服务层
// *
// * @author ruoyi
// */
//public interface ISysUserOnlineService
//{
// /**
// * 通过登录地址查询信息
// *
// * @param ipaddr 登录地址
// * @param user 用户信息
// * @return 在线用户信息
// */
// public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user);
//
// /**
// * 通过用户名称查询信息
// *
// * @param userName 用户名称
// * @param user 用户信息
// * @return 在线用户信息
// */
// public SysUserOnline selectOnlineByUserName(String userName, LoginUser user);
//
// /**
// * 通过登录地址/用户名称查询信息
// *
// * @param ipaddr 登录地址
// * @param userName 用户名称
// * @param user 用户信息
// * @return 在线用户信息
// */
// public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user);
//
// /**
// * 设置在线用户信息
// *
// * @param user 用户信息
// * @return 在线用户
// */
// public SysUserOnline loginUserToUserOnline(LoginUser user);
//}

View File

@@ -2,9 +2,11 @@ package com.ruoyi.system.service.impl;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SysClientDetailsMapper; import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.system.domain.SysClientDetails; import com.ruoyi.system.domain.SysClientDetails;
import com.ruoyi.system.mapper.SysClientDetailsMapper;
import com.ruoyi.system.service.ISysClientDetailsService; import com.ruoyi.system.service.ISysClientDetailsService;
/** /**
@@ -61,6 +63,7 @@ public class SysClientDetailsServiceImpl implements ISysClientDetailsService
* @return 结果 * @return 结果
*/ */
@Override @Override
@CacheEvict(value = CacheConstants.CLIENT_DETAILS_KEY, key = "#sysClientDetails.clientId")
public int updateSysClientDetails(SysClientDetails sysClientDetails) public int updateSysClientDetails(SysClientDetails sysClientDetails)
{ {
return sysClientDetailsMapper.updateSysClientDetails(sysClientDetails); return sysClientDetailsMapper.updateSysClientDetails(sysClientDetails);
@@ -73,20 +76,9 @@ public class SysClientDetailsServiceImpl implements ISysClientDetailsService
* @return 结果 * @return 结果
*/ */
@Override @Override
@CacheEvict(value = CacheConstants.CLIENT_DETAILS_KEY, allEntries = true)
public int deleteSysClientDetailsByIds(String[] clientIds) public int deleteSysClientDetailsByIds(String[] clientIds)
{ {
return sysClientDetailsMapper.deleteSysClientDetailsByIds(clientIds); return sysClientDetailsMapper.deleteSysClientDetailsByIds(clientIds);
} }
/**
* 删除终端配置信息
*
* @param clientId 终端配置ID
* @return 结果
*/
@Override
public int deleteSysClientDetailsById(String clientId)
{
return sysClientDetailsMapper.deleteSysClientDetailsById(clientId);
}
} }

View File

@@ -147,6 +147,7 @@ public class SysConfigServiceImpl implements ISysConfigService
/** /**
* 清空缓存数据 * 清空缓存数据
*/ */
@Override
public void clearCache() public void clearCache()
{ {
Collection<String> keys = redisService.keys(Constants.SYS_CONFIG_KEY + "*"); Collection<String> keys = redisService.keys(Constants.SYS_CONFIG_KEY + "*");

View File

@@ -62,6 +62,7 @@ public class SysDictDataServiceImpl implements ISysDictDataService
* @param dictCodes 需要删除的字典数据ID * @param dictCodes 需要删除的字典数据ID
* @return 结果 * @return 结果
*/ */
@Override
public int deleteDictDataByIds(Long[] dictCodes) public int deleteDictDataByIds(Long[] dictCodes)
{ {
int row = dictDataMapper.deleteDictDataByIds(dictCodes); int row = dictDataMapper.deleteDictDataByIds(dictCodes);

View File

@@ -107,6 +107,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
* @param dictType 字典类型 * @param dictType 字典类型
* @return 字典类型 * @return 字典类型
*/ */
@Override
public SysDictType selectDictTypeByType(String dictType) public SysDictType selectDictTypeByType(String dictType)
{ {
return dictTypeMapper.selectDictTypeByType(dictType); return dictTypeMapper.selectDictTypeByType(dictType);
@@ -118,6 +119,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
* @param dictIds 需要删除的字典ID * @param dictIds 需要删除的字典ID
* @return 结果 * @return 结果
*/ */
@Override
public int deleteDictTypeByIds(Long[] dictIds) public int deleteDictTypeByIds(Long[] dictIds)
{ {
for (Long dictId : dictIds) for (Long dictId : dictIds)
@@ -139,6 +141,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
/** /**
* 清空缓存数据 * 清空缓存数据
*/ */
@Override
public void clearCache() public void clearCache()
{ {
DictUtils.clearDictCache(); DictUtils.clearDictCache();

View File

@@ -121,6 +121,7 @@ public class SysMenuServiceImpl implements ISysMenuService
* @param roleId 角色ID * @param roleId 角色ID
* @return 选中菜单列表 * @return 选中菜单列表
*/ */
@Override
public List<Integer> selectMenuListByRoleId(Long roleId) public List<Integer> selectMenuListByRoleId(Long roleId)
{ {
return menuMapper.selectMenuListByRoleId(roleId); return menuMapper.selectMenuListByRoleId(roleId);

View File

@@ -86,6 +86,7 @@ public class SysNoticeServiceImpl implements ISysNoticeService
* @param noticeIds 需要删除的公告ID * @param noticeIds 需要删除的公告ID
* @return 结果 * @return 结果
*/ */
@Override
public int deleteNoticeByIds(Long[] noticeIds) public int deleteNoticeByIds(Long[] noticeIds)
{ {
return noticeMapper.deleteNoticeByIds(noticeIds); return noticeMapper.deleteNoticeByIds(noticeIds);

View File

@@ -48,6 +48,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService
* @param operIds 需要删除的操作日志ID * @param operIds 需要删除的操作日志ID
* @return 结果 * @return 结果
*/ */
@Override
public int deleteOperLogByIds(Long[] operIds) public int deleteOperLogByIds(Long[] operIds)
{ {
return operLogMapper.deleteOperLogByIds(operIds); return operLogMapper.deleteOperLogByIds(operIds);

View File

@@ -22,9 +22,10 @@ public class SysPermissionServiceImpl implements ISysPermissionService
/** /**
* 获取角色数据权限 * 获取角色数据权限
* *
* @param user 用户信息 * @param userId 用户Id
* @return 角色权限信息 * @return 角色权限信息
*/ */
@Override
public Set<String> getRolePermission(Long userId) public Set<String> getRolePermission(Long userId)
{ {
Set<String> roles = new HashSet<String>(); Set<String> roles = new HashSet<String>();
@@ -43,9 +44,10 @@ public class SysPermissionServiceImpl implements ISysPermissionService
/** /**
* 获取菜单数据权限 * 获取菜单数据权限
* *
* @param user 用户信息 * @param userId 用户Id
* @return 菜单权限信息 * @return 菜单权限信息
*/ */
@Override
public Set<String> getMenuPermission(Long userId) public Set<String> getMenuPermission(Long userId)
{ {
Set<String> perms = new HashSet<String>(); Set<String> perms = new HashSet<String>();

View File

@@ -68,6 +68,7 @@ public class SysPostServiceImpl implements ISysPostService
* @param userId 用户ID * @param userId 用户ID
* @return 选中岗位ID列表 * @return 选中岗位ID列表
*/ */
@Override
public List<Integer> selectPostListByUserId(Long userId) public List<Integer> selectPostListByUserId(Long userId)
{ {
return postMapper.selectPostListByUserId(userId); return postMapper.selectPostListByUserId(userId);
@@ -140,6 +141,7 @@ public class SysPostServiceImpl implements ISysPostService
* @return 结果 * @return 结果
* @throws Exception 异常 * @throws Exception 异常
*/ */
@Override
public int deletePostByIds(Long[] postIds) public int deletePostByIds(Long[] postIds)
{ {
for (Long postId : postIds) for (Long postId : postIds)

View File

@@ -81,6 +81,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* *
* @return 角色列表 * @return 角色列表
*/ */
@Override
public List<SysRole> selectRoleAll() public List<SysRole> selectRoleAll()
{ {
return SpringUtils.getAopProxy(this).selectRoleList(new SysRole()); return SpringUtils.getAopProxy(this).selectRoleList(new SysRole());
@@ -92,6 +93,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @param userId 用户ID * @param userId 用户ID
* @return 选中角色ID列表 * @return 选中角色ID列表
*/ */
@Override
public List<Integer> selectRoleListByUserId(Long userId) public List<Integer> selectRoleListByUserId(Long userId)
{ {
return roleMapper.selectRoleListByUserId(userId); return roleMapper.selectRoleListByUserId(userId);
@@ -103,6 +105,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @param roleId 角色ID * @param roleId 角色ID
* @return 角色对象信息 * @return 角色对象信息
*/ */
@Override
public SysRole selectRoleById(Long roleId) public SysRole selectRoleById(Long roleId)
{ {
return roleMapper.selectRoleById(roleId); return roleMapper.selectRoleById(roleId);
@@ -149,6 +152,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* *
* @param role 角色信息 * @param role 角色信息
*/ */
@Override
public void checkRoleAllowed(SysRole role) public void checkRoleAllowed(SysRole role)
{ {
if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin())
@@ -207,6 +211,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @param role 角色信息 * @param role 角色信息
* @return 结果 * @return 结果
*/ */
@Override
public int updateRoleStatus(SysRole role) public int updateRoleStatus(SysRole role)
{ {
return roleMapper.updateRole(role); return roleMapper.updateRole(role);
@@ -296,6 +301,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @param roleIds 需要删除的角色ID * @param roleIds 需要删除的角色ID
* @return 结果 * @return 结果
*/ */
@Override
public int deleteRoleByIds(Long[] roleIds) public int deleteRoleByIds(Long[] roleIds)
{ {
for (Long roleId : roleIds) for (Long roleId : roleIds)

View File

@@ -1,95 +0,0 @@
//package com.ruoyi.system.service.impl;
//
//import org.springframework.stereotype.Service;
//
//import com.ruoyi.common.core.utils.StringUtils;
//import com.ruoyi.system.domain.SysUserOnline;
//import com.ruoyi.system.service.ISysUserOnlineService;
//
///**
// * 在线用户 服务层处理
// *
// * @author ruoyi
// */
//@Service
//public class SysUserOnlineServiceImpl implements ISysUserOnlineService
//{
// /**
// * 通过登录地址查询信息
// *
// * @param ipaddr 登录地址
// * @param user 用户信息
// * @return 在线用户信息
// */
// @Override
// public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user)
// {
// if (StringUtils.equals(ipaddr, user.getIpaddr()))
// {
// return loginUserToUserOnline(user);
// }
// return null;
// }
//
// /**
// * 通过用户名称查询信息
// *
// * @param userName 用户名称
// * @param user 用户信息
// * @return 在线用户信息
// */
// @Override
// public SysUserOnline selectOnlineByUserName(String userName, LoginUser user)
// {
// if (StringUtils.equals(userName, user.getUsername()))
// {
// return loginUserToUserOnline(user);
// }
// return null;
// }
//
// /**
// * 通过登录地址/用户名称查询信息
// *
// * @param ipaddr 登录地址
// * @param userName 用户名称
// * @param user 用户信息
// * @return 在线用户信息
// */
// @Override
// public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user)
// {
// if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
// {
// return loginUserToUserOnline(user);
// }
// return null;
// }
//
// /**
// * 设置在线用户信息
// *
// * @param user 用户信息
// * @return 在线用户
// */
// public SysUserOnline loginUserToUserOnline(LoginUser user)
// {
// if (StringUtils.isNull(user) && StringUtils.isNull(user.getUser()))
// {
// return null;
// }
// SysUserOnline sysUserOnline = new SysUserOnline();
// sysUserOnline.setTokenId(user.getToken());
// sysUserOnline.setUserName(user.getUsername());
// sysUserOnline.setIpaddr(user.getIpaddr());
// sysUserOnline.setLoginLocation(user.getLoginLocation());
// sysUserOnline.setBrowser(user.getBrowser());
// sysUserOnline.setOs(user.getOs());
// sysUserOnline.setLoginTime(user.getLoginTime());
// if (StringUtils.isNotNull(user.getUser().getDept()))
// {
// sysUserOnline.setDeptName(user.getUser().getDept().getDeptName());
// }
// return sysUserOnline;
// }
//}

View File

@@ -194,6 +194,7 @@ public class SysUserServiceImpl implements ISysUserService
* *
* @param user 用户信息 * @param user 用户信息
*/ */
@Override
public void checkUserAllowed(SysUser user) public void checkUserAllowed(SysUser user)
{ {
if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())
@@ -270,10 +271,11 @@ public class SysUserServiceImpl implements ISysUserService
/** /**
* 修改用户头像 * 修改用户头像
* *
* @param userId 用户ID * @param userName 用户
* @param avatar 头像地址 * @param avatar 头像地址
* @return 结果 * @return 结果
*/ */
@Override
public boolean updateUserAvatar(String userName, String avatar) public boolean updateUserAvatar(String userName, String avatar)
{ {
return userMapper.updateUserAvatar(userName, avatar) > 0; return userMapper.updateUserAvatar(userName, avatar) > 0;
@@ -378,6 +380,7 @@ public class SysUserServiceImpl implements ISysUserService
* @param userIds 需要删除的用户ID * @param userIds 需要删除的用户ID
* @return 结果 * @return 结果
*/ */
@Override
public int deleteUserByIds(Long[] userIds) public int deleteUserByIds(Long[] userIds)
{ {
for (Long userId : userIds) for (Long userId : userIds)

View File

@@ -37,8 +37,8 @@ public class DictUtils
Object cacheObj = SpringUtils.getBean(RedisService.class).getCacheObject(getCacheKey(key)); Object cacheObj = SpringUtils.getBean(RedisService.class).getCacheObject(getCacheKey(key));
if (StringUtils.isNotNull(cacheObj)) if (StringUtils.isNotNull(cacheObj))
{ {
List<SysDictData> DictDatas = StringUtils.cast(cacheObj); List<SysDictData> dictDatas = StringUtils.cast(cacheObj);
return DictDatas; return dictDatas;
} }
return null; return null;
} }

View File

@@ -77,7 +77,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="checkDeptNameUnique" resultMap="SysDeptResult"> <select id="checkDeptNameUnique" resultMap="SysDeptResult">
<include refid="selectDeptVo"/> <include refid="selectDeptVo"/>
where dept_name=#{deptName} and parent_id = #{parentId} where dept_name=#{deptName} and parent_id = #{parentId} limit 1
</select> </select>
<insert id="insertDept" parameterType="SysDept"> <insert id="insertDept" parameterType="SysDept">

View File

@@ -1,30 +1,30 @@
## 开发 ## 开发
```bash ```bash
# 克隆项目 # 克隆项目
git clone https://gitee.com/y_project/RuoYi-Vue git clone https://gitee.com/y_project/RuoYi-Vue
# 进入项目目录 # 进入项目目录
cd ruoyi-ui cd ruoyi-ui
# 安装依赖 # 安装依赖
npm install npm install
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 # 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org npm install --registry=https://registry.npm.taobao.org
# 启动服务 # 启动服务
npm run dev npm run dev
``` ```
浏览器访问 http://localhost:80 浏览器访问 http://localhost:80
## 发布 ## 发布
```bash ```bash
# 构建测试环境 # 构建测试环境
npm run build:stage npm run build:stage
# 构建生产环境 # 构建生产环境
npm run build:prod npm run build:prod
``` ```

View File

@@ -1,5 +1,13 @@
module.exports = { module.exports = {
presets: [ presets: [
'@vue/app' // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
] '@vue/cli-plugin-babel/preset'
],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
'plugins': ['dynamic-import-node']
}
}
} }

View File

@@ -1,11 +1,11 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "2.3.0", "version": "2.1.0",
"description": "若依管理系统", "description": "若依管理系统",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"dev": "vue-cli-service serve --open", "dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build", "build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging", "build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview", "preview": "node build/index.js --preview",
@@ -43,10 +43,11 @@
"@riophae/vue-treeselect": "0.4.0", "@riophae/vue-treeselect": "0.4.0",
"axios": "0.18.1", "axios": "0.18.1",
"clipboard": "2.0.4", "clipboard": "2.0.4",
"core-js": "3.6.5",
"echarts": "4.2.1", "echarts": "4.2.1",
"element-ui": "2.13.0", "element-ui": "2.13.2",
"file-saver": "2.0.1", "file-saver": "2.0.1",
"js-beautify": "^1.10.2", "js-beautify": "1.10.2",
"fuse.js": "3.4.4", "fuse.js": "3.4.4",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",
"jsencrypt": "3.0.0-rc.1", "jsencrypt": "3.0.0-rc.1",
@@ -65,35 +66,31 @@
"vuex": "3.1.0" "vuex": "3.1.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.0.0", "@vue/cli-plugin-babel": "4.4.4",
"@babel/register": "7.0.0", "@vue/cli-plugin-eslint": "4.4.4",
"@babel/parser": "^7.7.4", "@vue/cli-plugin-unit-jest": "4.4.4",
"@vue/cli-plugin-babel": "3.5.3", "@vue/cli-service": "4.4.4",
"@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-plugin-unit-jest": "3.5.3",
"@vue/cli-service": "3.5.3",
"@vue/test-utils": "1.0.0-beta.29", "@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "^9.5.1", "autoprefixer": "9.5.1",
"babel-core": "7.0.0-bridge.0", "babel-eslint": "10.1.0",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0", "babel-jest": "23.6.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "2.4.2", "chalk": "2.4.2",
"chokidar": "2.1.5", "chokidar": "2.1.5",
"connect": "3.6.6", "connect": "3.6.6",
"eslint": "5.15.3", "eslint": "6.7.2",
"eslint-plugin-vue": "5.2.2", "eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "3.2.0", "html-webpack-plugin": "3.2.0",
"http-proxy-middleware": "^0.19.1",
"husky": "1.3.1", "husky": "1.3.1",
"lint-staged": "8.1.5", "lint-staged": "8.1.5",
"mockjs": "1.0.1-beta3", "mockjs": "1.0.1-beta3",
"node-sass": "^4.9.0",
"plop": "2.3.0", "plop": "2.3.0",
"runjs": "^4.3.2", "runjs": "4.3.2",
"sass-loader": "^7.1.0", "sass": "1.26.10",
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.3", "script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2", "script-loader": "0.7.2",
"serve-static": "^1.13.2", "serve-static": "1.13.2",
"svg-sprite-loader": "4.1.3", "svg-sprite-loader": "4.1.3",
"svgo": "1.2.0", "svgo": "1.2.0",
"vue-template-compiler": "2.6.10" "vue-template-compiler": "2.6.10"

View File

@@ -2,11 +2,11 @@ import request from '@/utils/request'
const client_id = 'web' const client_id = 'web'
const client_secret = '123456' const client_secret = '123456'
const grant_type = 'password'
const scope = 'server' const scope = 'server'
// 登录方法 // 登录方法
export function login(username, password, code, uuid) { export function login(username, password, code, uuid) {
const grant_type = 'password'
return request({ return request({
url: '/auth/oauth/token', url: '/auth/oauth/token',
method: 'post', method: 'post',
@@ -14,6 +14,16 @@ export function login(username, password, code, uuid) {
}) })
} }
// 刷新方法
export function refreshToken(refresh_token) {
const grant_type = 'refresh_token'
return request({
url: '/auth/oauth/token',
method: 'post',
params: { client_id, client_secret, grant_type, scope, refresh_token }
})
}
// 获取用户详细信息 // 获取用户详细信息
export function getInfo() { export function getInfo() {
return request({ return request({

View File

@@ -1,18 +0,0 @@
import request from '@/utils/request'
// 查询在线用户列表
export function list(query) {
return request({
url: '/monitor/online/list',
method: 'get',
params: query
})
}
// 强退用户
export function forceLogout(tokenId) {
return request({
url: '/monitor/online/' + tokenId,
method: 'delete'
})
}

View File

@@ -42,6 +42,7 @@ export function importTable(data) {
params: data params: data
}) })
} }
// 预览生成代码 // 预览生成代码
export function previewTable(tableId) { export function previewTable(tableId) {
return request({ return request({
@@ -49,6 +50,7 @@ export function previewTable(tableId) {
method: 'get' method: 'get'
}) })
} }
// 删除表数据 // 删除表数据
export function delTable(tableId) { export function delTable(tableId) {
return request({ return request({
@@ -57,3 +59,10 @@ export function delTable(tableId) {
}) })
} }
// 生成代码(自定义路径)
export function genCode(tableName) {
return request({
url: '/code/gen/genCode/' + tableName,
method: 'get'
})
}

View File

@@ -142,7 +142,28 @@
padding-left: 15px; padding-left: 15px;
margin-bottom: 10px; margin-bottom: 10px;
} }
/* button color */
.el-button--cyan.is-active,
.el-button--cyan:active {
background: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
}
.el-button--cyan:focus,
.el-button--cyan:hover {
background: #48D1CC;
border-color: #48D1CC;
color: #FFFFFF;
}
.el-button--cyan {
background-color: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
}
/* text color */ /* text color */
.text-navy { .text-navy {
color: #1ab394; color: #1ab394;
@@ -198,4 +219,8 @@
opacity: .8; opacity: .8;
color: #fff!important; color: #fff!important;
background: #42b983!important; background: #42b983!important;
}
.top-right-btn {
float: right;
} }

View File

@@ -167,7 +167,7 @@ export default {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
/deep/ .el-input__inner { ::v-deep .el-input__inner {
border-radius: 0; border-radius: 0;
border: 0; border: 0;
padding-left: 0; padding-left: 0;

View File

@@ -94,7 +94,7 @@ export default {
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.$store.dispatch('LogOut').then(() => { this.$store.dispatch('LogOut').then(() => {
location.reload() location.href = '/index';
}) })
}) })
} }

Some files were not shown because too many files have changed in this diff Show More