合并分支 'safety-202304' 到 'master'

Safety 202304

查看合并请求 JeroBoot/jero-boot!15
This commit is contained in:
李雪涛
2023-04-14 09:35:16 +08:00
30 changed files with 1627 additions and 156 deletions
@@ -279,6 +279,16 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
return Collections.emptyList();
}
@Override
public List<SysDictItemCore> getDictItemAll() {
return Collections.emptyList();
}
@Override
public String queryTableDictTextByKey(String table, String text, String code, String key) {
return null;
}
@Override
public void sendEmailMsg(String email,String title,String content) {
// do other
@@ -119,4 +119,23 @@ public interface CommonAPI {
* @return
*/
List<DictModel> translateDictFromTableByKeys(String table, String text, String code, String keys);
/**
* 14获取全部字典
* @author lqt
* @date 2022/8/16 8:54
* @return JSONObject
*/
List<SysDictItemCore> getDictItemAll();;
/**
* 15通过查询指定table的 text code 获取字典值text
* @author lqt
* @date 2022/8/16 8:54
* @param table 表名
* @param text 文本
* @param code 编码
* @param key 键
* @return JSONObject
*/
String queryTableDictTextByKey(String table,String text,String code, String key);
}
@@ -0,0 +1,57 @@
package com.jero.common.aspect;
import com.jero.common.aspect.annotation.RedisLock;
import com.jero.common.exception.JeroBootException;
import com.jero.common.util.RedisLockHelper;
import com.jero.common.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.UUID;
/**
* 分布式部署定时任务
* @Author lqt
*/
@Slf4j
@Aspect
@Component
public class LockMethodAspect {
@Resource
private RedisLockHelper redisLockHelper;
@Resource
private RedisUtil redisUtis;
@Around("@annotation(com.jero.common.aspect.annotation.RedisLock)")
public Object around(ProceedingJoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
RedisLock redisLock = method.getAnnotation(RedisLock.class);
String value = UUID.randomUUID().toString();
log.info("====value=====" + value + "===========");
String key = redisLock.key();
log.info("====key======" + key + "===========");
try {
final boolean islock = redisLockHelper.lock(redisUtis, key, value, redisLock.expire(), redisLock.timeUnit());
log.info("isLock : {}", islock);
if (!islock) {
log.error("获取锁失败");
throw new JeroBootException("获取锁失败");
}
try {
return joinPoint.proceed();
} catch (Throwable throwable) {
throw new JeroBootException("系统异常");
}
} finally {
log.info("释放锁");
redisLockHelper.unlock(redisUtis, key, value);
}
}
}
@@ -0,0 +1,181 @@
package com.jero.common.aspect;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jero.common.api.CommonAPI;
import com.jero.common.api.vo.Results;
import com.jero.common.aspect.annotation.Dict;
import com.jero.common.constant.CommonConstant;
import com.jero.common.system.vo.SysDictItemCore;
import com.jero.common.util.oConvertUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Description 对controller接口返回值翻译,不支持多层嵌套翻译
* @Author lqt
* @Date 2022/6/7 17:08
* @Version 1.0
*/
@Slf4j
@Aspect
@Component
@SuppressWarnings({"unused"})
public class TranslationAspect {
@Resource
private CommonAPI commonAPI;
@Pointcut("@annotation(com.jero.common.aspect.annotation.Translation)")
public void annotationPointcut() {
// do other
}
@Before("annotationPointcut()")
public void beforePointcut(JoinPoint joinPoint) {
// 此处进入到方法前 可以实现一些业务逻辑
}
@Around("annotationPointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();
this.parseDictText(result);
return result;
}
/**
* 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
* @param joinPoint
*/
@AfterReturning(returning="rvt",pointcut = "annotationPointcut()")
public void doAfterReturning(JoinPoint joinPoint, Object rvt) {
}
private void parseDictText(Object result) {
List<SysDictItemCore> listDict = commonAPI.getDictItemAll();
if(CollectionUtils.isEmpty(listDict)){
return;
}
if (result instanceof Results) {
if (((Results) result).getResult() instanceof IPage) {
List<Object> items = new ArrayList<>();
for (Object record : ((IPage) ((Results) result).getResult()).getRecords()) {
Object item = translateObject(record,listDict);
items.add(item);
}
((IPage) ((Results) result).getResult()).setRecords(items);
}else if (((Results) result).getResult() instanceof List) {
List<Object> items = new ArrayList<>();
for (Object record : ((List) ((Results) result).getResult())) {
Object item = translateObject(record,listDict);
items.add(item);
}
((Results) result).setResult(items);
}else{
Object record = (Object) ((Results) result).getResult();
Object item = translateObject(record,listDict);
((Results) result).setResult(item);
}
}
}
private Object translateObject(Object record,List<SysDictItemCore> listDict){
ObjectMapper mapper = new ObjectMapper();
String json;
try {
//解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
json = mapper.writeValueAsString(record);
} catch (JsonProcessingException e) {
log.error("json解析失败" + e.getMessage(), e);
return record;
}
JSONObject item;
try {
item = JSONObject.parseObject(json);
//update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
//for (Field field : record.getClass().getDeclaredFields()) {
for (Field field : oConvertUtils.getAllFields(record)) {
//update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
if (field.getAnnotation(Dict.class) != null) {
String code = field.getAnnotation(Dict.class).dicCode();
String text = field.getAnnotation(Dict.class).dicText();
String table = field.getAnnotation(Dict.class).dictTable();
String key = String.valueOf(item.get(field.getName()));
//翻译字典值对应的txt
String textValue = translateDictValue(code, text, table, key, listDict);
item.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);
}
//date类型默认转换string格式化日期
if (Objects.equals(field.getType().getName(),"java.util.Date") && field.getAnnotation(JsonFormat.class) == null && item.get(field.getName()) != null) {
SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
}
}
}catch (Exception e){
log.info("########################此返回类型不支持字典翻译########################");
return record;
}
return item;
}
/**
* 翻译字典文本
* @param code 编码
* @param text 值
* @param table 表名
* @param key 键
* @param listDict 字典集合
*/
private String translateDictValue(String code, String text, String table, String key, List<SysDictItemCore> listDict) {
if(oConvertUtils.isEmpty(key)) {
return null;
}
StringBuilder textValue = new StringBuilder();
String[] keys = key.split(",");
for (String k : keys) {
String tmpValue = null;
if (k.trim().length() == 0) {
continue; //跳过循环
}
if (!StringUtils.isEmpty(table)){
tmpValue = commonAPI.queryTableDictTextByKey(table,text,code,k.trim());
}else {
// tmpValue = dictService.queryDictTextByKey(code, k.trim());
List<SysDictItemCore> listNew = listDict.stream().filter(o-> Objects.equals(o.getDictCode(),code) && Objects.equals(o.getItemValue(),k.trim())).collect(Collectors.toList());
if(!CollectionUtils.isEmpty(listNew)){
tmpValue = listNew.get(0).getItemText();
}
}
if (tmpValue != null) {
if (!"".equals(textValue.toString())) {
textValue.append(",");
}
textValue.append(tmpValue);
}
}
return textValue.toString();
}
}
@@ -0,0 +1,24 @@
package com.jero.common.aspect.annotation;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @author LQT
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RedisLock {
/*** 业务键** @return*/
String key();
/*** 锁的过期秒数,默认是5秒** @return*/
int expire() default 5;
/*** 尝试加锁,最多等待时间** @return*/
long waitTime() default Long.MIN_VALUE;
/*** 锁的超时时间单位** @return*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
@@ -0,0 +1,14 @@
package com.jero.common.aspect.annotation;
import java.lang.annotation.*;
/**
* 只适用controller层,在controller上添加此注解,该注解对返回结果进行翻译,不支持多层嵌套
* @author LQT
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Translation {
}
@@ -0,0 +1,87 @@
package com.jero.common.system.vo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.jero.common.aspect.annotation.Dict;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
*
* </p>
*
* @Author zhangweijian
* @since 2018-12-28
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class SysDictItemCore implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private String id;
/**
* 字典id
*/
private String dictId;
/**
* 字典编码
*/
@TableField(exist = false)
private String dictCode;
/**
* 字典项文本
*/
@Excel(name = "字典项文本", width = 20)
private String itemText;
/**
* 字典项值
*/
@Excel(name = "字典项值", width = 30)
private String itemValue;
/**
* 描述
*/
@Excel(name = "描述", width = 40)
private String description;
/**
* 排序
*/
@Excel(name = "排序", width = 15,type=4)
private Integer sortOrder;
/**
* 状态(1启用 0不启用)
*/
@Dict(dicCode = "dict_item_status")
private Integer status;
private String createBy;
private Date createTime;
private String updateBy;
private Date updateTime;
}
@@ -0,0 +1,116 @@
package com.jero.common.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class RedisLockHelper {
private long sleepTime = 100;
/**
* 直接使用setnx + expire方式获取分布式锁
* 非原子性
*
* @param key
* @param value
* @param timeout
* @return
*/
public boolean lockSetNx(RedisUtil redisTemplate, String key, String value, int timeout) {
if ( redisTemplate.setnx(key, value)) {
return redisTemplate.expire(key, timeout);
} else {
return false;
}
}
/**
* 使用Lua脚本,脚本中使用setnex+expire命令进行加锁操作
*
* @param redisTemplate
* @param key
* @param uniqueId
* @param seconds
* @return
*/
public boolean lockWithLua(RedisUtil redisTemplate, String key, String uniqueId, int seconds) {
if(!Objects.isNull(seconds)){
log.info("未使用参数:" + seconds);
}
String luaScript = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then" +
"redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end";
Object result = redisTemplate.eval(RedisScript.of(luaScript), Collections.singletonList(key), uniqueId);
//判断是否成功
return result.equals(1L);
}
/**
* 在Redis的2.6.12及以后中,使用 set key value [NX] [EX] 命令
*
* @param key
* @param value
* @param timeout
* @return
*/
public boolean lock(RedisUtil redisTemplate, String key, String value, int timeout, TimeUnit timeUnit) {
long seconds = timeUnit.toSeconds(timeout);
return redisTemplate.setnx(key, value, seconds);
}
/**
* 自定义获取锁的超时时间
*
* @param redisTemplate
* @param key
* @param value
* @param timeout
* @param waitTime
* @param timeUnit
* @return
* @throws InterruptedException
*/
public boolean lockWithWaitTime(RedisUtil redisTemplate, String key, String value, int timeout, long waitTime, TimeUnit timeUnit) throws InterruptedException {
long seconds = timeUnit.toSeconds(timeout);
while (waitTime >= 0) {
if (redisTemplate.setnx(key, value, seconds)) {
return true;
}
waitTime -= sleepTime;
Thread.sleep(sleepTime);
}
return false;
}
/**
* 错误的解锁方法—直接删除key
*
* @param key
*/
public void unlockWithDel(RedisUtil redisTemplate, String key) {
redisTemplate.del(key);
}
/**
* 使用Lua脚本进行解锁操纵,解锁的时候验证value值
*
* @param redisTemplate
* @param key
* @param value
* @return
*/
public boolean unlock(RedisUtil redisTemplate, String key, String value) {
String luaScript = "if redis.call('get',KEYS[1]) == ARGV[1] then " +
"return redis.call('del',KEYS[1]) else return 0 end";
DefaultRedisScript<Long> redisScript =new DefaultRedisScript<> ();
redisScript.setScriptText(luaScript);
// 这个值类型要跟lua返回值类型一致才行,否则就会报 java.lang.IllegalStateException
redisScript.setResultType(Long.class);
return redisTemplate.eval(redisScript, Collections.singletonList(key), value);
}
}
@@ -1,126 +0,0 @@
package com.jero.config;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jero.common.api.vo.Results;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* 描述:跨站过滤器
*
* @Author: 马志朝
* @Date: 2021/4/16 14:09
*/
@Component
public class CsrfFilter implements Filter {
private static final String UNKNOWN_CONSTANT = "unknown";
/**
* LOGGER
*/
private static final Log LOGGER = LogFactory.getLog(CsrfFilter.class);
/**
* 白名单
*/
@Value("${jero.whiteUrls}")
private List<String> whiteUrls;
/**
* size
*/
private int size = 0;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
size = whiteUrls.size();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
try {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 获取请求url地址
String url = req.getRequestURL().toString();
// 获取来源
String referurl = req.getHeader("Referer");
if(isWhiteReq(referurl)){
chain.doFilter(request, response);
}else{
String log = "";
String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String ip = getIp(req);
log = "跨站请求---->>>" + ip + "||" + date + "||" + referurl + "||" + url;
LOGGER.warn(log);
//发送错误信息
JSONObject json = JSONUtil.parseObj(Results.error("监测到跨站请求,请求失败"), false);
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json; charset=utf-8");
PrintWriter out = res.getWriter();
out.append(json.toStringPretty());
}
} catch (Exception e) {
LOGGER.error("doFilter", e);
}
}
/**
* 判断是否是白名单
*/
private boolean isWhiteReq(String referUrl) {
if (referUrl == null || "".equals(referUrl) || size == 0) {
return true;
} else {
String refHost = "";
referUrl = referUrl.toLowerCase();
if (referUrl.startsWith("http://")) {
refHost = referUrl.substring(7);
} else if (referUrl.startsWith("https://")) {
refHost = referUrl.substring(8);
}
for (String urlTemp : whiteUrls) {
if (refHost.contains(urlTemp.toLowerCase())) {
return true;
}
}
}
return false;
}
/**
* 获取登录用户IP地址
* @param request
* @return
*/
public String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || UNKNOWN_CONSTANT.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN_CONSTANT.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN_CONSTANT.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.equals("0:0:0:0:0:0:0:1")) {
ip = "localhost";
}
return ip;
}
@Override
public void destroy() {
// do other
}
}
@@ -0,0 +1,62 @@
package com.jero.config;
import com.jero.config.filter.cors.CorsFilter;
import com.jero.config.filter.csrf.CsrfFilter;
import com.jero.config.filter.xss.XssFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* @author hzwl
*/
@Configuration
public class WebConfig {
@Value("${jero.xssExcludedPages}")
private List<String> xssExcluded;
@Value("${jero.notFilter}")
private List<String> notFilter;
@Value("${jero.originIp}")
private String originIp;
/**
* 白名单
*/
@Value("${jero.whiteUrls}")
private List<String> whiteUrls;
@Bean
public FilterRegistrationBean<CsrfFilter> csrfFilter() {
FilterRegistrationBean<CsrfFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CsrfFilter(whiteUrls));
registration.addUrlPatterns("/*");
registration.setName("csrfFilter");
registration.setOrder(1);
return registration;
}
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CorsFilter(originIp,notFilter));
registration.addUrlPatterns("/*");
registration.setName("corsFilter");
registration.setOrder(2);
return registration;
}
@Bean
public FilterRegistrationBean<XssFilter> xssFilter() {
FilterRegistrationBean<XssFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new XssFilter(xssExcluded));
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setOrder(3);
return filterRegistrationBean;
}
}
@@ -53,23 +53,6 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
registry.addViewController("/").setViewName("doc.html");
}
@Bean
@Conditional(CorsFilterCondition.class)
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
//是否允许请求带有验证信息
corsConfiguration.setAllowCredentials(true);
// 允许访问的客户端域名
corsConfiguration.addAllowedOrigin("*");
// 允许服务端访问的客户端请求头
corsConfiguration.addAllowedHeader("*");
// 允许访问的方法名,GET POST等
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
/**
* 添加Long转json精度丢失的配置
* @Return: void
@@ -0,0 +1,89 @@
package com.jero.config.filter.cors;
import org.apache.commons.lang3.ArrayUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
/**
* @author hzwl
* 设置响应信息
*/
@WebFilter(urlPatterns = {"/verifyCode/**"})
public class CorsFilter implements Filter {
private final String originIp;
private final List<String> notFilter;
public CorsFilter(String originIp, List<String> notFilter) {
this.originIp = originIp;
this.notFilter = notFilter;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// do other
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
final String origin = ((HttpServletRequest) request).getHeader("Origin");
//请求头与系统的origin不通则咔嚓
String[] split = originIp.split(",");
if (Objects.nonNull(origin) && !ArrayUtils.contains(split,origin)){
return;
}
//获取请求路径
String url = req.getRequestURL().toString();
if (!isMSBrowser(req)){
for (String name : notFilter) {
//如果包含,不需要判断Origin是否合法
if(url.contains(name)){
responseInfo(request, response, chain);
return;
}
}
}
responseInfo(request, response, chain);
}
public boolean isMSBrowser(HttpServletRequest request) {
String[] ieBrowserSignals = {"MSIE", "Trident"};
String userAgent = request.getHeader("User-Agent");
for (String signal : ieBrowserSignals) {
if (userAgent.contains(signal)){
return true;
}
}
return false;
}
private void responseInfo(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-Control-Allow-Origin", originIp);
httpServletResponse.addHeader("Access-Control-Allow-Headers", "Authorization");
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST,GET");
httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
httpServletResponse.setHeader("Content-Security-Policy", "upgrade-insecure-requests;connect-src *");
httpServletResponse.setHeader("X-Content-Type-Options", "nosniff");
httpServletResponse.setHeader("X-XSS-Protection", "1;mode=block");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Origin, Accept, x-auth-token, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, authorization");
chain.doFilter(request, response);
}
@Override
public void destroy() {
// do other
}
}
@@ -0,0 +1,131 @@
package com.jero.config.filter.csrf;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jero.common.api.vo.Results;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* 描述:跨站过滤器
*
* @Author: 马志朝
* @Date: 2021/4/16 14:09
*/
public class CsrfFilter implements Filter {
/**
* LOGGER
*/
private static final Log LOGGER = LogFactory.getLog(CsrfFilter.class);
private final List<String> whiteUrls;
/**
* size
*/
private int size = 0;
public CsrfFilter(List<String> whiteUrls) {
this.whiteUrls = whiteUrls;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
size = whiteUrls.size();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 获取是否为websocket链接
String upgrade = req.getHeader("Upgrade");
// 获取来源
String referurl = req.getHeader("Referer");
if(isWhiteReq(referurl) || Objects.equals(upgrade,"websocket")){
chain.doFilter(request, response);
}else{
// 获取请求url地址
String url = req.getRequestURL().toString();
String log = "";
String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String ip = getIp(req);
log = "跨站请求---->>>" + ip + "||" + date + "||" + referurl + "||" + url;
LOGGER.warn(log);
//发送错误信息
JSONObject json = JSONUtil.parseObj(Results.error("监测到跨站请求,请求失败"), false);
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json; charset=utf-8");
PrintWriter out = res.getWriter();
out.append(json.toStringPretty());
}
}
/**
* 判断是否是白名单
*/
private boolean isWhiteReq(String referUrl) {
try {
if (referUrl == null || "".equals(referUrl) || size == 0) {
return false;
} else {
String refHost = "";
referUrl = referUrl.toLowerCase();
if (referUrl.startsWith("http://")) {
int i = referUrl.indexOf("/", 7) - 7;
refHost = referUrl.substring(7,i+7);
} else if (referUrl.startsWith("https://")) {
int i = referUrl.indexOf("/", 8) - 8;
refHost = referUrl.substring(8,i+8);
}
for (String urlTemp : whiteUrls) {
if (refHost.equals(urlTemp.toLowerCase())) {
return true;
}
}
}
return false;
}catch (Exception e){
LOGGER.error("doFilter", e);
return false;
}
}
/**
* 获取登录用户IP地址
* @param request
* @return
*/
public String getIp(HttpServletRequest request) {
String unknown = "unknown";
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.equals("0:0:0:0:0:0:0:1")) {
ip = "localhost";
}
return ip;
}
@Override
public void destroy() {
// do other
}
}
@@ -0,0 +1,398 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.jero.config.filter.xss;
import cn.hutool.core.lang.Console;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author hzwl
*/
public final class HTMLFilter {
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", 32);
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", 34);
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", 32);
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", 34);
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", 34);
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", 34);
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", 34);
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", 34);
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+)(<|$)", 32);
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_QUOTE = Pattern.compile("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']");
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
private final Map<String, List<String>> vAllowed;
private final Map<String, Integer> vTagCounts;
private final String[] vSelfClosingTags;
private final String[] vNeedClosingTags;
private final String[] vDisallowed;
private final String[] vProtocolAtts;
private final String[] vAllowedProtocols;
private final String[] vRemoveBlanks;
private final String[] vAllowedEntities;
private final boolean stripComment;
private final boolean encodeQuotes;
private boolean vDebug;
private final boolean alwaysMakeTags;
public HTMLFilter() {
String strong = "strong";
this.vTagCounts = new HashMap<>();
this.vDebug = false;
this.vAllowed = new HashMap<>();
ArrayList<String> aAtts = new ArrayList<>();
aAtts.add("href");
aAtts.add("target");
this.vAllowed.put("a", aAtts);
ArrayList<String> imgAtts = new ArrayList<>();
imgAtts.add("src");
imgAtts.add("width");
imgAtts.add("height");
imgAtts.add("alt");
this.vAllowed.put("img", imgAtts);
ArrayList<String> noAtts = new ArrayList<>();
this.vAllowed.put("b", noAtts);
this.vAllowed.put(strong, noAtts);
this.vAllowed.put("i", noAtts);
this.vAllowed.put("em", noAtts);
this.vSelfClosingTags = new String[]{"img"};
this.vNeedClosingTags = new String[]{"a", "b", strong, "i", "em"};
this.vDisallowed = new String[0];
this.vAllowedProtocols = new String[]{"http", "mailto", "https"};
this.vProtocolAtts = new String[]{"src", "href"};
this.vRemoveBlanks = new String[]{"a", "b", strong, "i", "em"};
this.vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
this.stripComment = true;
this.encodeQuotes = true;
this.alwaysMakeTags = true;
}
private void reset() {
this.vTagCounts.clear();
}
private void debug(String msg) {
if (this.vDebug) {
Console.log(msg);
}
}
public static String chr(int decimal) {
return String.valueOf((char)decimal);
}
public static String htmlSpecialChars(String s) {
String result = regexReplace(P_QUOTE, "&quot;", s);
result = regexReplace(P_LEFT_ARROW, "&lt;", result);
result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
return result;
}
public String filter(String input) {
this.reset();
this.debug("************************************************");
this.debug(" INPUT: " + input);
String s = this.escapeComments(input);
this.debug(" escapeComments: " + s);
s = this.balanceHTML(s);
this.debug(" balanceHTML: " + s);
s = this.checkTags(s);
this.debug(" checkTags: " + s);
s = this.processRemoveBlanks(s);
this.debug("processRemoveBlanks: " + s);
this.debug("************************************************\n\n");
return s;
}
private String escapeComments(String s) {
Matcher m = P_COMMENTS.matcher(s);
StringBuffer buf = new StringBuffer();
if (m.find()) {
String match = m.group(1);
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
}
m.appendTail(buf);
return buf.toString();
}
private String balanceHTML(String s) {
if (this.alwaysMakeTags) {
// do other
} else {
s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
s = regexReplace(P_BOTH_ARROWS, "", s);
}
return s;
}
private String checkTags(String s) {
Matcher m = P_TAGS.matcher(s);
StringBuffer buf = new StringBuffer();
while(m.find()) {
String replaceStr = m.group(1);
replaceStr = this.processTag(replaceStr);
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
}
m.appendTail(buf);
StringBuilder sBuilder = new StringBuilder(buf.toString());
for (Map.Entry<String, Integer> entry : this.vTagCounts.entrySet()) {
sBuilder.append("</").append(entry.getKey()).append(">");
}
s = sBuilder.toString();
return s;
}
private String processRemoveBlanks(String s) {
String result = s;
String[] var3 = this.vRemoveBlanks;
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
String tag = var3[var5];
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
}
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
}
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
}
return result;
}
private static String regexReplace(Pattern regexPattern, String replacement, String s) {
Matcher m = regexPattern.matcher(s);
return m.replaceAll(replacement);
}
private String processTag(String s) {
Matcher m = P_END_TAG.matcher(s);
String name;
if (m.find()) {
name = m.group(1).toLowerCase();
if (this.allowed(name) && !inArray(name, this.vSelfClosingTags) && this.vTagCounts.containsKey(name)) {
this.vTagCounts.put(name, this.vTagCounts.get(name) - 1);
return "</" + name + ">";
}
}
m = P_START_TAG.matcher(s);
if (!m.find()) {
m = P_COMMENT.matcher(s);
return !this.stripComment && m.find() ? "<" + m.group() + ">" : "";
} else {
name = m.group(1).toLowerCase();
String body = m.group(2);
String ending = m.group(3);
if (!this.allowed(name)) {
return "";
} else {
StringBuilder params = new StringBuilder();
Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
List<String> paramNames = new ArrayList<>();
ArrayList<String> paramValues = new ArrayList<>();
getAppend(name, params, m2, m3, paramNames, paramValues);
ending = getString(name, ending);
return "<" + name + params + ending + ">";
}
}
}
@Nullable
private String getString(String name, String ending) {
if (inArray(name, this.vSelfClosingTags)) {
ending = " /";
}
if (inArray(name, this.vNeedClosingTags)) {
ending = "";
}
if (ending != null && ending.length() >= 1) {
ending = " /";
} else if (this.vTagCounts.containsKey(name)) {
this.vTagCounts.put(name, this.vTagCounts.get(name) + 1);
} else {
this.vTagCounts.put(name, 1);
}
return ending;
}
private void getAppend(String name, StringBuilder params, Matcher m2, Matcher m3, List<String> paramNames, ArrayList<String> paramValues) {
while(m2.find()) {
paramNames.add(m2.group(1));
paramValues.add(m2.group(3));
}
while(m3.find()) {
paramNames.add(m3.group(1));
paramValues.add(m3.group(3));
}
for(int ii = 0; ii < paramNames.size(); ++ii) {
String paramName = paramNames.get(ii).toLowerCase();
String paramValue = paramValues.get(ii);
if (this.allowedAttribute(name, paramName)) {
if (inArray(paramName, this.vProtocolAtts)) {
paramValue = this.processParamProtocol(paramValue);
}
params.append(' ').append(paramName).append("=\"").append(paramValue).append("\"");
}
}
}
private String processParamProtocol(String s) {
s = this.decodeEntities(s);
Matcher m = P_PROTOCOL.matcher(s);
if (m.find()) {
String protocol = m.group(1);
if (!inArray(protocol, this.vAllowedProtocols)) {
s = "#" + s.substring(protocol.length() + 1);
if (s.startsWith("#//")) {
s = "#" + s.substring(3);
}
}
}
return s;
}
private String decodeEntities(String s) {
StringBuffer buf = new StringBuffer();
Matcher m = P_ENTITY.matcher(s);
String match;
int decimal;
while(m.find()) {
match = m.group(1);
decimal = Integer.decode(match);
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
buf = new StringBuffer();
m = P_ENTITY_UNICODE.matcher(s);
while(m.find()) {
match = m.group(1);
decimal = Integer.valueOf(match, 16);
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
buf = new StringBuffer();
while(m.find()) {
match = m.group(1);
decimal = Integer.valueOf(match, 16);
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
s = this.validateEntities(s);
return s;
}
private String validateEntities(String s) {
StringBuffer buf = new StringBuffer();
Matcher m = P_VALID_ENTITIES.matcher(s);
while(m.find()) {
String one = m.group(1);
String two = m.group(2);
m.appendReplacement(buf, Matcher.quoteReplacement(this.checkEntity(one, two)));
}
m.appendTail(buf);
return this.encodeQuotes(buf.toString());
}
private String encodeQuotes(String s) {
if (!this.encodeQuotes) {
return s;
} else {
StringBuffer buf = new StringBuffer();
Matcher m = P_VALID_QUOTES.matcher(s);
while(m.find()) {
String one = m.group(1);
String two = m.group(2);
String three = m.group(3);
m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));
}
m.appendTail(buf);
return buf.toString();
}
}
private String checkEntity(String preamble, String term) {
return ";".equals(term) && this.isValidEntity(preamble) ? '&' + preamble : "&amp;" + preamble;
}
private boolean isValidEntity(String entity) {
return inArray(entity, this.vAllowedEntities);
}
private static boolean inArray(String s, String[] array) {
String[] var2 = array;
int var3 = array.length;
for(int var4 = 0; var4 < var3; ++var4) {
String item = var2[var4];
if (item != null && item.equals(s)) {
return true;
}
}
return false;
}
private boolean allowed(String name) {
return (this.vAllowed.isEmpty() || this.vAllowed.containsKey(name)) && !inArray(name, this.vDisallowed);
}
private boolean allowedAttribute(String name, String paramName) {
return this.allowed(name) && (this.vAllowed.isEmpty() || this.vAllowed.get(name).contains(paramName));
}
}
@@ -0,0 +1,35 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.jero.config.filter.xss;
import com.jero.common.exception.JeroBootException;
import org.apache.commons.lang.StringUtils;
public class SqlFilter {
private SqlFilter(){
}
public static String sqlInject(String str) {
if (StringUtils.isBlank(str)) {
return null;
} else {
str = StringUtils.replace(str, "\\n", "Line_Break");
String[] keywords = new String[]{"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
String[] var2 = keywords;
int var3 = keywords.length;
for(int var4 = 0; var4 < var3; ++var4) {
String keyword = var2[var4];
if (StringUtils.indexOfIgnoreCase(str, keyword + " ") != -1) {
throw new JeroBootException("包含非法字符");
}
}
str = StringUtils.replace(str, "Line_Break", "\\n");
return str;
}
}
}
@@ -0,0 +1,58 @@
package com.jero.config.filter.xss;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
/**
* @author hzwl
*/
public class XssFilter implements Filter {
private final List<String> excludedPages;
public XssFilter(List<String> excludedPages) {
this.excludedPages=excludedPages;
}
@Override
public void init(FilterConfig config) throws ServletException {
// do other
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean isExcludedPage = false;
for (String excludedPage : excludedPages) {
if (((HttpServletRequest)request).getRequestURI().contains(excludedPage)) {
isExcludedPage = true;
break;
}
}
if (isExcludedPage) {
chain.doFilter(request, response);
} else {
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest)request);
chain.doFilter(xssRequest, response);
}
}
@Override
public void destroy() {
// do other
}
public static String filterNull(Object o) {
return o != null && !"null".equals(o.toString()) ? o.toString().trim() : "";
}
public static boolean isNotEmpty(Object o) {
if (o == null) {
return false;
} else {
return !"".equals(filterNull(o.toString()));
}
}
}
@@ -0,0 +1,130 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.jero.config.filter.xss;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author hzwl
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
HttpServletRequest orgRequest;
private static final HTMLFilter HTML_FILTER = new HTMLFilter();
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.orgRequest = request;
}
@Override
public ServletInputStream getInputStream() throws IOException {
String type = super.getHeader("Content-Type");
if (StringUtils.indexOfIgnoreCase(type, "application/json") < 0) {
return super.getInputStream();
} else {
String json = IOUtils.toString(super.getInputStream(), StandardCharsets.UTF_8);
if (StringUtils.isBlank(json)) {
return super.getInputStream();
} else {
json = this.xssSqlEncode(json);
final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
return new ServletInputStream() {
@Override
public boolean isFinished() {
return true;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
// do other
}
@Override
public int read() throws IOException {
return bis.read();
}
};
}
}
}
@Override
public String getParameter(String name) {
String value = super.getParameter(this.xssSqlEncode(name));
if (StringUtils.isNotBlank(value)) {
value = this.xssSqlEncode(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] parameters = super.getParameterValues(name);
if (parameters != null && parameters.length != 0) {
for(int i = 0; i < parameters.length; ++i) {
parameters[i] = this.xssSqlEncode(parameters[i]);
}
return parameters;
} else {
return new String[0];
}
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = new LinkedHashMap<>();
Map<String, String[]> parameters = super.getParameterMap();
for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
String[] values = entry.getValue();
for (int i = 0; i < values.length; ++i) {
values[i] = this.xssSqlEncode(values[i]);
}
map.put(entry.getKey(), values);
}
return map;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(this.xssSqlEncode(name));
if (StringUtils.isNotBlank(value)) {
value = this.xssSqlEncode(value);
}
return value;
}
private String xssSqlEncode(String input) {
input=input.replace("%5b","[").replace("%5d","]");
String htmlOutput= HTML_FILTER.filter(input);
return SqlFilter.sqlInject(htmlOutput);
}
public HttpServletRequest getOrgRequest() {
return this.orgRequest;
}
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
return request instanceof XssHttpServletRequestWrapper ? ((XssHttpServletRequestWrapper)request).getOrgRequest() : request;
}
}
@@ -125,8 +125,8 @@ public class ShiroConfig {
//filterChainDefinitionMap.put("/test/JeroDemo/html", "anon"); //模板页面
//filterChainDefinitionMap.put("/test/JeroDemo/redis/**", "anon"); //redis测试
//websocket排除
filterChainDefinitionMap.put("/websocket/**", "anon");//系统通知和公告
// websocket排除
filterChainDefinitionMap.put("/websocket/**", "anon");
filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块
filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例
@@ -1,10 +1,12 @@
package com.jero.common.util;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@@ -609,4 +611,37 @@ public class RedisUtil {
e.printStackTrace();
}
}
/**
* setnx
*/
public boolean setnx(String key, String value) {
try {
return redisTemplate.opsForValue().setIfAbsent(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* setnx
*/
public boolean setnx(String key, String value,long time) {
try {
return redisTemplate.opsForValue().setIfAbsent(key,value, Duration.ofSeconds(time));
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* eval
*/
public Boolean eval(RedisScript<Long> luaScripts, List<String> keys, String values) {
Long flag = redisTemplate.execute(luaScripts, keys, values);
//判断是不是为1
return flag == 1L;
}
}
@@ -1,12 +1,16 @@
package com.jero.modules.quartz.job;
import com.jero.common.aspect.annotation.RedisLock;
import com.jero.common.util.DateUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
/**
* 示例带参定时任务
*
@@ -25,6 +29,7 @@ public class SampleParamJob implements Job {
}
@Override
@RedisLock(key = "lock----TestJob",expire=60,timeUnit= TimeUnit.SECONDS)
public void execute(JobExecutionContext jobExecutionContext) {
log.info(" Job Execution key"+jobExecutionContext.getJobDetail().getKey());
log.info("welcome " + this.parameter + " Jero-Boot 带参数定时任务 SampleParamJob ! 时间:" + DateUtils.now());
@@ -0,0 +1,87 @@
package com.jero.modules.system.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.jero.common.aspect.annotation.Dict;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
*
* </p>
*
* @Author zhangweijian
* @since 2018-12-28
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class SysDictItemCore implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private String id;
/**
* 字典id
*/
private String dictId;
/**
* 字典编码
*/
@TableField(exist = false)
private String dictCode;
/**
* 字典项文本
*/
@Excel(name = "字典项文本", width = 20)
private String itemText;
/**
* 字典项值
*/
@Excel(name = "字典项值", width = 30)
private String itemValue;
/**
* 描述
*/
@Excel(name = "描述", width = 40)
private String description;
/**
* 排序
*/
@Excel(name = "排序", width = 15,type=4)
private Integer sortOrder;
/**
* 状态(1启用 0不启用)
*/
@Dict(dicCode = "dict_item_status")
private Integer status;
private String createBy;
private Date createTime;
private String updateBy;
private Date updateTime;
}
@@ -17,4 +17,14 @@ import java.util.List;
public interface SysDictItemMapper extends BaseMapper<SysDictItem> {
@Select("SELECT * FROM sys_dict_item WHERE DICT_ID = #{mainId} order by sort_order asc, item_value asc")
public List<SysDictItem> selectItemsByMainId(String mainId);
// /**
// * 获取字典所有数据
// * @author LQT
// * @Date 2022/5/13 14:22
// * @param
// * @return java.util.List<com.jero.system.dict.entity.SysDictItem>
// */
// List<SysDictItem> getDictItemAll();
}
@@ -2,4 +2,9 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jero.modules.system.mapper.SysDictItemMapper">
<!-- <select id="getDictItemAll" resultType="com.jero.modules.system.entity.SysDictItem">-->
<!-- SELECT tsdi.*,tsd.dict_code FROM sys_dict_item tsdi-->
<!-- LEFT JOIN sys_dict tsd ON tsdi.dict_id = tsd.id-->
<!-- WHERE status = 1-->
<!-- </select>-->
</mapper>
@@ -36,7 +36,7 @@
<!-- 通过字典code获取字典数据 -->
<select id="queryDictTextByKey" parameterType="String" resultType="String">
select s.item_text from sys_dict_item s
select s.item_text from sys_dict_item s
where s.dict_id = (select id from sys_dict where dict_code = #{code})
and s.item_value = #{key}
</select>
@@ -66,7 +66,7 @@
<select id="queryTableDictItemsByCode" parameterType="String" resultType="com.jero.common.system.vo.DictModel">
select ${text} as "text",${code} as "value" from ${table}
</select>
<!--通过查询指定table的 text code 获取字典(指定查询条件)-->
<select id="queryTableDictItemsByCodeAndFilter" parameterType="String" resultType="com.jero.common.system.vo.DictModel">
select ${text} as "text",${code} as "value" from ${table}
@@ -74,7 +74,7 @@
where ${filterSql}
</if>
</select>
<!--通过查询指定table的 text code key 获取字典值-->
<select id="queryTableDictTextByKey" parameterType="String" resultType="String">
select ${text} as "text" from ${table} where ${code}= #{key}
@@ -88,7 +88,7 @@
</foreach>
)
</select>
<!--通过查询指定table的 text code key 获取字典值,包含value-->
<select id="queryTableDictByKeys" parameterType="String" resultType="com.jero.common.system.vo.DictModel">
select ${text} as "text", ${code} as "value" from ${table} where ${code} in
@@ -100,28 +100,34 @@
<!-- 重复校验 sql语句 -->
<select id="duplicateCheckCountSql" resultType="Long" parameterType="com.jero.modules.system.model.DuplicateCheckVo">
SELECT COUNT(*) FROM ${tableName} WHERE ${fieldName} = #{fieldVal} and id &lt;&gt; #{dataId}
<if test="tableName == 'sys_user' or tableName == 'sys_depart'">
and del_flag = 0
</if>
</select>
<!-- 重复校验 sql语句 -->
<select id="duplicateCheckCountSqlNoDataId" resultType="Long" parameterType="com.jero.modules.system.model.DuplicateCheckVo">
SELECT COUNT(*) FROM ${tableName} WHERE ${fieldName} = #{fieldVal}
<if test="tableName == 'sys_user' or tableName == 'sys_depart'">
and del_flag = 0
</if>
</select>
<!-- 查询部门信息 作为字典数据 -->
<select id="queryAllDepartBackDictModel" resultType="com.jero.common.system.vo.DictModel">
select id as "value",depart_name as "text" from sys_depart where del_flag = '0'
</select>
<!-- 查询用户信息 作为字典数据 -->
<select id="queryAllUserBackDictModel" resultType="com.jero.common.system.vo.DictModel">
select username as "value",realname as "text" from sys_user where del_flag = '0'
</select>
<!--通过查询指定table的 text code 获取字典数据,且支持关键字查询 -->
<select id="queryTableDictItems" parameterType="String" resultType="com.jero.common.system.vo.DictModel">
select ${text} as "text",${code} as "value" from ${table} where ${text} like #{keyword}
</select>
<!-- 根据表名、显示字段名、存储字段名、父ID查询树 -->
<select id="queryTreeList" parameterType="Object" resultType="com.jero.modules.system.model.TreeSelectModel">
select ${text} as "title",
@@ -15,4 +15,13 @@ import java.util.List;
*/
public interface ISysDictItemService extends IService<SysDictItem> {
public List<SysDictItem> selectItemsByMainId(String mainId);
/**
* 获取字典所有数据
* @author LQT
* @Date 2022/5/13 14:22
* @param
* @return java.util.List<com.jero.system.dict.entity.SysDictItem>
*/
List<SysDictItem> getDictItemAll();
}
@@ -19,6 +19,7 @@ import com.jero.common.exception.JeroBootException;
import com.jero.common.system.api.ISysBaseAPI;
import com.jero.common.system.query.QueryGenerator;
import com.jero.common.system.vo.*;
import com.jero.common.system.vo.SysDictItemCore;
import com.jero.common.util.SysAnnmentTypeEnum;
import com.jero.common.util.YouBianCodeUtil;
import com.jero.common.util.oConvertUtils;
@@ -40,6 +41,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import javax.annotation.Resource;
@@ -94,6 +96,11 @@ public class SysBaseApiImpl implements ISysBaseAPI {
@Autowired
private ISysPermissionDataRuleService sysPermissionDataRuleService;
@Resource
private ISysDictService dictService;
@Resource
private ISysDictItemService sysDictItemService;
@Autowired
ISysCategoryService sysCategoryService;
private static final String ERROR_MSG = "消息模板不存在,模板编码:";
@@ -1151,4 +1158,19 @@ public class SysBaseApiImpl implements ISysBaseAPI {
return sysDictService.queryTableDictTextByKeys(table, text, code, Arrays.asList(keys.split(",")));
}
@Override
public List<SysDictItemCore> getDictItemAll() {
List<SysDictItem> listSysDictItem = sysDictItemService.getDictItemAll();
List<SysDictItemCore> listSysDictItemCore = new ArrayList<>();
if(!CollectionUtils.isEmpty(listSysDictItem)){
listSysDictItemCore = JSONObject.parseArray(JSON.toJSONString(listSysDictItem),SysDictItemCore.class);
}
return listSysDictItemCore;
}
@Override
public String queryTableDictTextByKey(String table, String text, String code, String key) {
return dictService.queryTableDictTextByKey(table,text,code,key);
}
}
@@ -27,4 +27,10 @@ public class SysDictItemServiceImpl extends ServiceImpl<SysDictItemMapper, SysDi
public List<SysDictItem> selectItemsByMainId(String mainId) {
return sysDictItemMapper.selectItemsByMainId(mainId);
}
@Override
public List<SysDictItem> getDictItemAll() {
// return sysDictItemMapper.getDictItemAll();
return null;
}
}
@@ -272,7 +272,13 @@ jero:
# 文件限制后缀黑名单
fileSuffixLimits : 0x00,%00,\\00,.jsp,.exe,.php,.asp,.aspx,.jspx,.xml,.html,.js,.sh,.bin
# 跨站白名单
whiteUrls:
whiteUrls: localhost:3000
# xss白名单
xssExcludedPages: /login,/updatePassword
# cors白名单
notFilter:
# origin地址
originIp: http://localhost:3000
# 加密默认值
password:
pbe:
@@ -274,6 +274,12 @@ jero:
fileSuffixLimits : 0x00,%00,\\00,.jsp,.exe,.php,.asp,.aspx,.jspx,.xml,.html,.js,.sh,.bin
# 跨站白名单
whiteUrls:
# xss白名单
xssExcludedPages: /login,/updatePassword
# cors白名单
notFilter:
# origin地址
originIp: http://localhost:3000
# 加密默认值
password:
pbe:
@@ -272,7 +272,13 @@ jero:
# 文件限制后缀黑名单
fileSuffixLimits : 0x00,%00,\\00,.jsp,.exe,.php,.asp,.aspx,.jspx,.xml,.html,.js,.sh,.bin
# 跨站白名单
whiteUrls:
whiteUrls: localhost:3000
# xss白名单
xssExcludedPages: /login,/updatePassword
# cors白名单
notFilter:
# origin地址
originIp: http://localhost:3000
# 加密默认值
password:
pbe: