合并分支 'safety-202304' 到 'master'
Safety 202304 查看合并请求 JeroBoot/jero-boot!15
This commit is contained in:
+10
@@ -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
|
||||
|
||||
+19
@@ -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);
|
||||
}
|
||||
|
||||
+57
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+181
@@ -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();
|
||||
}
|
||||
}
|
||||
+24
@@ -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;
|
||||
}
|
||||
+14
@@ -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 {
|
||||
|
||||
}
|
||||
+87
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
+116
@@ -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);
|
||||
}
|
||||
}
|
||||
-126
@@ -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
|
||||
}
|
||||
}
|
||||
+62
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
-17
@@ -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
|
||||
|
||||
+89
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
+131
@@ -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
|
||||
}
|
||||
}
|
||||
+398
@@ -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, """, s);
|
||||
result = regexReplace(P_LEFT_ARROW, "<", result);
|
||||
result = regexReplace(P_RIGHT_ARROW, ">", 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, "<$1", s);
|
||||
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", 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, """, two) + three));
|
||||
}
|
||||
|
||||
m.appendTail(buf);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String checkEntity(String preamble, String term) {
|
||||
return ";".equals(term) && this.isValidEntity(preamble) ? '&' + preamble : "&" + 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));
|
||||
}
|
||||
}
|
||||
+35
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
+130
@@ -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;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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无痕刷新示例
|
||||
|
||||
|
||||
+35
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -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());
|
||||
|
||||
+87
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
+10
@@ -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();
|
||||
}
|
||||
|
||||
+5
@@ -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>
|
||||
|
||||
+15
-9
@@ -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 <> #{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",
|
||||
|
||||
+9
@@ -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();
|
||||
}
|
||||
|
||||
+22
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user