整合提交

This commit is contained in:
2026-06-23 18:46:45 +08:00
parent 32e35666af
commit 0b4860f46e
452 changed files with 21755 additions and 23 deletions
+16
View File
@@ -0,0 +1,16 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.weather</groupId>
<artifactId>weather-data</artifactId>
<version>5.5.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>system-common</artifactId>
<packaging>jar</packaging>
<description>system-common</description>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
@@ -0,0 +1,42 @@
package com.weather.common.aspect;
import com.weather.common.exception.ErrorCode;
import com.weather.common.exception.CommonException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Redis切面处理类
*
* @author 123
*/
@Aspect
@Component
public class RedisAspect {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 是否开启redis缓存 true开启 false关闭
*/
@Value("${weather.redis.open: false}")
private boolean open;
@Around("execution(* com.weather.common.redis.RedisUtils.*(..))")
public Object around(ProceedingJoinPoint point) throws Throwable {
Object result = null;
if (open) {
try {
result = point.proceed();
} catch (Exception e) {
logger.error("redis error", e);
throw new CommonException(ErrorCode.REDIS_ERROR);
}
}
return result;
}
}
@@ -0,0 +1,154 @@
package com.weather.common.constant;
/**
* 常量
*
* @author 123
*/
public interface Constant {
/**
* 成功
*/
int SUCCESS = 1;
/**
* 失败
*/
int FAIL = 0;
/**
* 菜单根节点标识
*/
Long MENU_ROOT = 0L;
/**
* 部门根节点标识
*/
Long DEPT_ROOT = 0L;
/**
* 升序
*/
String ASC = "asc";
/**
* 降序
*/
String DESC = "desc";
/**
* 创建时间字段名
*/
String CREATE_DATE = "create_date";
/**
* 数据权限过滤
*/
String SQL_FILTER = "sqlFilter";
/**
* 当前页码
*/
String PAGE = "page";
/**
* 每页显示记录数
*/
String LIMIT = "limit";
/**
* 排序字段
*/
String ORDER_FIELD = "orderField";
/**
* 排序方式
*/
String ORDER = "order";
/**
* token header
*/
String TOKEN_HEADER = "token";
/**
* 云存储配置KEY
*/
String CLOUD_STORAGE_CONFIG_KEY = "CLOUD_STORAGE_CONFIG_KEY";
/**
* 文件扫描根路径KEY
*/
String FILE_SCAN_ROOT_PATH = "FILE_SCAN_ROOT_PATH";
/**
* 文件扫描状态
*/
enum FileScanStatus {
/**
* 已接收
*/
RECEIVED(0),
/**
* 展示中
*/
DISPLAYED(1),
/**
* 已归档
*/
ARCHIVED(2);
private int value;
FileScanStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
/**
* 定时任务状态
*/
enum ScheduleStatus {
/**
* 暂停
*/
PAUSE(0),
/**
* 正常
*/
NORMAL(1);
private int value;
ScheduleStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
/**
* 云服务商
*/
enum CloudService {
/**
* 七牛云
*/
QINIU(1),
/**
* 阿里云
*/
ALIYUN(2),
/**
* 腾讯云
*/
QCLOUD(3);
private int value;
CloudService(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
}
@@ -0,0 +1,73 @@
package com.weather.common.convert;
import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 日期转换
*
* @author 123
*/
@Component
public class DateConverter implements Converter<String, Date> {
private static final Logger logger = LoggerFactory.getLogger(DateConverter.class);
private static final List<String> formatList = new ArrayList<>(5);
static {
formatList.add("yyyy-MM");
formatList.add("yyyy-MM-dd");
formatList.add("yyyy-MM-dd HH:mm");
formatList.add("yyyy-MM-dd HH:mm:ss");
formatList.add("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
}
@Override
public Date convert(String source) {
String value = source.trim();
if (StrUtil.isEmpty(value)) {
return null;
}
if (source.matches("^\\d{4}-\\d{1,2}$")) {
return parseDate(source, formatList.get(0));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {
return parseDate(source, formatList.get(1));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$")) {
return parseDate(source, formatList.get(2));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$")) {
return parseDate(source, formatList.get(3));
} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2}.*T.*\\d{1,2}:\\d{1,2}:\\d{1,2}.*..*$")) {
return parseDate(source, formatList.get(4));
} else {
throw new IllegalArgumentException("Invalid boolean value '" + source + "'");
}
}
/**
* 格式化日期
* @param dateStr String 字符型日期
* @param format String 格式
* @return Date 日期
*/
public Date parseDate(String dateStr, String format) {
Date date = null;
try {
DateFormat dateFormat = new SimpleDateFormat(format);
date = dateFormat.parse(dateStr);
} catch (Exception e) {
logger.error("Formatted date with date: {} and format : {} ", dateStr, format);
}
return date;
}
}
@@ -0,0 +1,15 @@
package com.weather.common.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 基础Dao
*
* @author 123
* @since 1.0.0
*/
public interface BaseDao<T> extends BaseMapper<T> {
}
@@ -0,0 +1,35 @@
package com.weather.common.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 基础实体类,所有实体都需要继承
*
* @author 123
*/
@Data
public abstract class BaseEntity implements Serializable {
/**
* id
*/
@TableId
private Long id;
/**
* 创建者
*/
@TableField(fill = FieldFill.INSERT)
private Long creator;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createDate;
}
@@ -0,0 +1,69 @@
package com.weather.common.exception;
import com.weather.common.utils.MessageUtils;
/**
* 自定义异常
*
* @author 123
*/
public class CommonException extends RuntimeException {
private static final long serialVersionUID = 1L;
private int code;
private String msg;
public CommonException(int code) {
this.code = code;
this.msg = MessageUtils.getMessage(code);
}
public CommonException(int code, String... params) {
this.code = code;
this.msg = MessageUtils.getMessage(code, params);
}
public CommonException(int code, Throwable e) {
super(e);
this.code = code;
this.msg = MessageUtils.getMessage(code);
}
public CommonException(int code, Throwable e, String... params) {
super(e);
this.code = code;
this.msg = MessageUtils.getMessage(code, params);
}
public CommonException(String msg) {
super(msg);
this.code = ErrorCode.INTERNAL_SERVER_ERROR;
this.msg = msg;
}
public CommonException(String msg, Throwable e) {
super(msg, e);
this.code = ErrorCode.INTERNAL_SERVER_ERROR;
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
@@ -0,0 +1,40 @@
package com.weather.common.exception;
/**
* 错误编码,由5位数字组成,前2位为模块编码,后3位为业务编码
* <p>
* 如:10001(10代表系统模块,001代表业务代码)
* </p>
*
* @author 123
* @since 1.0.0
*/
public interface ErrorCode {
int INTERNAL_SERVER_ERROR = 500;
int UNAUTHORIZED = 401;
int NOT_NULL = 10001;
int DB_RECORD_EXISTS = 10002;
int PARAMS_GET_ERROR = 10003;
int ACCOUNT_PASSWORD_ERROR = 10004;
int ACCOUNT_DISABLE = 10005;
int IDENTIFIER_NOT_NULL = 10006;
int CAPTCHA_ERROR = 10007;
int SUB_MENU_EXIST = 10008;
int PASSWORD_ERROR = 10009;
int SUPERIOR_DEPT_ERROR = 10011;
int SUPERIOR_MENU_ERROR = 10012;
int DATA_SCOPE_PARAMS_ERROR = 10013;
int DEPT_SUB_DELETE_ERROR = 10014;
int DEPT_USER_DELETE_ERROR = 10015;
int UPLOAD_FILE_EMPTY = 10019;
int TOKEN_NOT_EMPTY = 10020;
int TOKEN_INVALID = 10021;
int ACCOUNT_LOCK = 10022;
int OSS_UPLOAD_FILE_ERROR = 10024;
int REDIS_ERROR = 10027;
int JOB_ERROR = 10028;
int INVALID_SYMBOL = 10029;
}
@@ -0,0 +1,47 @@
package com.weather.common.exception;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* Exception工具类
*
* @author 123
*/
public class ExceptionUtils {
/**
* 获取异常信息
* @param ex 异常
* @return 返回异常信息
*/
public static String getErrorStackTrace(Exception ex){
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw, true);
ex.printStackTrace(pw);
}finally {
try {
if(pw != null) {
pw.close();
}
} catch (Exception e) {
}
try {
if(sw != null) {
sw.close();
}
} catch (IOException e) {
}
}
return sw.toString();
}
}
@@ -0,0 +1,36 @@
package com.weather.common.page;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 分页工具类
*
* @author 123
*/
@Data
@Schema(title = "分页数据")
public class PageData<T> implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(title = "总记录数")
private int total;
@Schema(title = "列表数据")
private List<T> list;
/**
* 分页
* @param list 列表数据
* @param total 总记录数
*/
public PageData(List<T> list, long total) {
this.list = list;
this.total = (int)total;
}
}
@@ -0,0 +1,49 @@
package com.weather.common.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis配置
*
* @author 123
*/
@Configuration
public class RedisConfig {
@Resource
private RedisConnectionFactory factory;
@Bean
public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer(){
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
// Spring Boot 3.5 新写法
return new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
}
@@ -0,0 +1,58 @@
package com.weather.common.redis;
/**
* @author 123
* @since 1.0.0
*/
public class RedisKeys {
/**
* 系统参数Key
*/
public static String getSysParamsKey(){
return "sys:params";
}
/**
* 验证码Key
*/
public static String getCaptchaKey(String uuid){
return "sys:captcha:" + uuid;
}
/**
* 登录用户Key
*/
public static String getSecurityUserKey(Long id){
return "sys:security:user:" + id;
}
/**
* 系统日志Key
*/
public static String getSysLogKey(){
return "sys:log";
}
/**
* 系统资源Key
*/
public static String getSysResourceKey(){
return "sys:resource";
}
/**
* 用户菜单导航Key
*/
public static String getUserMenuNavKey(Long userId){
return "sys:user:nav:" + userId;
}
/**
* 用户权限标识Key
*/
public static String getUserPermissionsKey(Long userId){
return "sys:user:permissions:" + userId;
}
}
@@ -0,0 +1,119 @@
package com.weather.common.redis;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Redis工具类
*
* @author 123
*/
@Component
public class RedisUtils {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/** 默认过期时长为24小时,单位:秒 */
public final static long DEFAULT_EXPIRE = 60 * 60 * 24L;
/** 过期时长为1小时,单位:秒 */
public final static long HOUR_ONE_EXPIRE = 60 * 60 * 1L;
/** 过期时长为6小时,单位:秒 */
public final static long HOUR_SIX_EXPIRE = 60 * 60 * 6L;
/** 不设置过期时长 */
public final static long NOT_EXPIRE = -1L;
public void set(String key, Object value, long expire) {
redisTemplate.opsForValue().set(key, value);
if (expire != NOT_EXPIRE) {
expire(key, expire);
}
}
public void set(String key, Object value) {
set(key, value, DEFAULT_EXPIRE);
}
public Object get(String key, long expire) {
Object value = redisTemplate.opsForValue().get(key);
if (expire != NOT_EXPIRE) {
expire(key, expire);
}
return value;
}
public Object get(String key) {
return get(key, NOT_EXPIRE);
}
public void delete(String key) {
redisTemplate.delete(key);
}
public void delete(Collection<String> keys) {
redisTemplate.delete(keys);
}
public Object hGet(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}
public Map<String, Object> hGetAll(String key) {
HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
return hashOperations.entries(key);
}
public void hMSet(String key, Map<String, Object> map) {
hMSet(key, map, DEFAULT_EXPIRE);
}
public void hMSet(String key, Map<String, Object> map, long expire) {
redisTemplate.opsForHash().putAll(key, map);
if (expire != NOT_EXPIRE) {
expire(key, expire);
}
}
public void hSet(String key, String field, Object value) {
hSet(key, field, value, DEFAULT_EXPIRE);
}
public void hSet(String key, String field, Object value, long expire) {
redisTemplate.opsForHash().put(key, field, value);
if (expire != NOT_EXPIRE) {
expire(key, expire);
}
}
public void expire(String key, long expire) {
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
public void hDel(String key, Object... fields) {
redisTemplate.opsForHash().delete(key, fields);
}
public void leftPush(String key, Object value) {
leftPush(key, value, DEFAULT_EXPIRE);
}
public void leftPush(String key, Object value, long expire) {
redisTemplate.opsForList().leftPush(key, value);
if (expire != NOT_EXPIRE) {
expire(key, expire);
}
}
public Object rightPop(String key) {
return redisTemplate.opsForList().rightPop(key);
}
}
@@ -0,0 +1,110 @@
package com.weather.common.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import java.io.Serializable;
import java.util.Collection;
/**
* 基础服务接口,所有Service接口都要继承
*
* @author 123
*/
public interface BaseService<T> {
Class<T> currentModelClass();
/**
* <p>
* 插入一条记录(选择字段,策略插入)
* </p>
*
* @param entity 实体对象
*/
boolean insert(T entity);
/**
* <p>
* 插入(批量),该方法不支持 Oracle、SQL Server
* </p>
*
* @param entityList 实体对象集合
*/
boolean insertBatch(Collection<T> entityList);
/**
* <p>
* 插入(批量),该方法不支持 Oracle、SQL Server
* </p>
*
* @param entityList 实体对象集合
* @param batchSize 插入批次数量
*/
boolean insertBatch(Collection<T> entityList, int batchSize);
/**
* <p>
* 根据 ID 选择修改
* </p>
*
* @param entity 实体对象
*/
boolean updateById(T entity);
/**
* <p>
* 根据 whereEntity 条件,更新记录
* </p>
*
* @param entity 实体对象
* @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
*/
boolean update(T entity, Wrapper<T> updateWrapper);
/**
* <p>
* 根据ID 批量更新
* </p>
*
* @param entityList 实体对象集合
*/
boolean updateBatchById(Collection<T> entityList);
/**
* <p>
* 根据ID 批量更新
* </p>
*
* @param entityList 实体对象集合
* @param batchSize 更新批次数量
*/
boolean updateBatchById(Collection<T> entityList, int batchSize);
/**
* <p>
* 根据 ID 查询
* </p>
*
* @param id 主键ID
*/
T selectById(Serializable id);
/**
* <p>
* 根据 ID 删除
* </p>
*
* @param id 主键ID
*/
boolean deleteById(Serializable id);
/**
* <p>
* 删除(根据ID 批量删除)
* </p>
*
* @param idList 主键ID列表
*/
boolean deleteBatchIds(Collection<? extends Serializable> idList);
}
@@ -0,0 +1,28 @@
package com.weather.common.service;
import com.weather.common.page.PageData;
import java.util.List;
import java.util.Map;
/**
* CRUD基础服务接口
*
* @author 123
*/
public interface CrudService<T, D> extends BaseService<T> {
PageData<D> page(Map<String, Object> params);
List<D> list(Map<String, Object> params);
D get(Long id);
void save(D dto);
void update(D dto);
void delete(Long[] ids);
}
@@ -0,0 +1,212 @@
package com.weather.common.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.weather.common.constant.Constant;
import com.weather.common.page.PageData;
import com.weather.common.service.BaseService;
import com.weather.common.utils.ConvertUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
/**
* 基础服务类,所有Service都要继承
*
* @author 123
*/
public abstract class BaseServiceImpl<M extends BaseMapper<T>, T> implements BaseService<T> {
@Autowired
protected M baseDao;
protected Log log = LogFactory.getLog(getClass());
/**
* 获取分页对象
* @param params 分页查询参数
* @param defaultOrderField 默认排序字段
* @param isAsc 排序方式
*/
protected IPage<T> getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
//分页参数
long curPage = 1;
long limit = 10;
if (params.get(Constant.PAGE) != null) {
curPage = Long.parseLong((String) params.get(Constant.PAGE));
}
if (params.get(Constant.LIMIT) != null) {
limit = Long.parseLong((String) params.get(Constant.LIMIT));
}
//分页对象
Page<T> page = new Page<>(curPage, limit);
//分页参数
params.put(Constant.PAGE, page);
//排序字段
String orderField = (String) params.get(Constant.ORDER_FIELD);
String order = (String) params.get(Constant.ORDER);
//前端字段排序
if (StrUtil.isNotBlank(orderField) && StrUtil.isNotBlank(order)) {
if (Constant.ASC.equalsIgnoreCase(order)) {
return page.addOrder(OrderItem.asc(orderField));
} else {
return page.addOrder(OrderItem.desc(orderField));
}
}
//没有排序字段,则不排序
if (StrUtil.isBlank(defaultOrderField)) {
return page;
}
//默认排序
if (isAsc) {
page.addOrder(OrderItem.asc(defaultOrderField));
} else {
page.addOrder(OrderItem.desc(defaultOrderField));
}
return page;
}
protected <T> PageData<T> getPageData(List<?> list, long total, Class<T> target) {
List<T> targetList = ConvertUtils.sourceToTarget(list, target);
return new PageData<>(targetList, total);
}
protected <T> PageData<T> getPageData(IPage page, Class<T> target) {
return getPageData(page.getRecords(), page.getTotal(), target);
}
protected void paramsToLike(Map<String, Object> params, String... likes) {
for (String like : likes) {
String val = (String) params.get(like);
if (StrUtil.isNotBlank(val)) {
params.put(like, "%" + val + "%");
} else {
params.put(like, null);
}
}
}
/**
* <p>
* 判断数据库操作是否成功
* </p>
* <p>
* 注意!! 该方法为 Integer 判断,不可传入 int 基本类型
* </p>
*
* @param result 数据库操作返回影响条数
* @return boolean
*/
protected static boolean retBool(Integer result) {
return SqlHelper.retBool(result);
}
protected Class<M> currentMapperClass() {
return (Class<M>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseServiceImpl.class, 0);
}
@Override
public Class<T> currentModelClass() {
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseServiceImpl.class, 1);
}
protected String getSqlStatement(SqlMethod sqlMethod) {
return SqlHelper.getSqlStatement(this.currentMapperClass(), sqlMethod);
}
@Override
public boolean insert(T entity) {
return BaseServiceImpl.retBool(baseDao.insert(entity));
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean insertBatch(Collection<T> entityList) {
return insertBatch(entityList, 100);
}
/**
* 批量插入
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean insertBatch(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
}
/**
* 执行批量操作
*/
protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
return SqlHelper.executeBatch(this.currentModelClass(), this.log, list, batchSize, consumer);
}
@Override
public boolean updateById(T entity) {
return BaseServiceImpl.retBool(baseDao.updateById(entity));
}
@Override
public boolean update(T entity, Wrapper<T> updateWrapper) {
return BaseServiceImpl.retBool(baseDao.update(entity, updateWrapper));
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateBatchById(Collection<T> entityList) {
return updateBatchById(entityList, 30);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(sqlStatement, param);
});
}
@Override
public T selectById(Serializable id) {
return baseDao.selectById(id);
}
@Override
public boolean deleteById(Serializable id) {
return SqlHelper.retBool(baseDao.deleteById(id));
}
@Override
public boolean deleteBatchIds(Collection<? extends Serializable> idList) {
return SqlHelper.retBool(baseDao.deleteBatchIds(idList));
}
}
@@ -0,0 +1,73 @@
package com.weather.common.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.weather.common.page.PageData;
import com.weather.common.service.CrudService;
import com.weather.common.utils.ConvertUtils;
import org.springframework.beans.BeanUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* CRUD基础服务类
*
* @author 123
*/
public abstract class CrudServiceImpl<M extends BaseMapper<T>, T, D> extends BaseServiceImpl<M, T> implements CrudService<T, D> {
protected Class<D> currentDtoClass() {
return (Class<D>)ReflectionKit.getSuperClassGenericType(getClass(), CrudServiceImpl.class, 2);
}
@Override
public PageData<D> page(Map<String, Object> params) {
IPage<T> page = baseDao.selectPage(
getPage(params, null, false),
getWrapper(params)
);
return getPageData(page, currentDtoClass());
}
@Override
public List<D> list(Map<String, Object> params) {
List<T> entityList = baseDao.selectList(getWrapper(params));
return ConvertUtils.sourceToTarget(entityList, currentDtoClass());
}
public abstract QueryWrapper<T> getWrapper(Map<String, Object> params);
@Override
public D get(Long id) {
T entity = baseDao.selectById(id);
return ConvertUtils.sourceToTarget(entity, currentDtoClass());
}
@Override
public void save(D dto) {
T entity = ConvertUtils.sourceToTarget(dto, currentModelClass());
insert(entity);
//copy主键值到dto
BeanUtils.copyProperties(entity, dto);
}
@Override
public void update(D dto) {
T entity = ConvertUtils.sourceToTarget(dto, currentModelClass());
updateById(entity);
}
@Override
public void delete(Long[] ids) {
baseDao.deleteByIds(Arrays.asList(ids));
}
}
@@ -0,0 +1,54 @@
package com.weather.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 转换工具类
*
* @author 123
*/
public class ConvertUtils {
private static Logger logger = LoggerFactory.getLogger(ConvertUtils.class);
public static <T> T sourceToTarget(Object source, Class<T> target){
if(source == null){
return null;
}
T targetObject = null;
try {
targetObject = target.newInstance();
BeanUtils.copyProperties(source, targetObject);
} catch (Exception e) {
logger.error("convert error ", e);
}
return targetObject;
}
public static <T> List<T> sourceToTarget(Collection<?> sourceList, Class<T> target){
if(sourceList == null){
return null;
}
List targetList = new ArrayList<>(sourceList.size());
try {
for(Object source : sourceList){
T targetObject = target.newInstance();
BeanUtils.copyProperties(source, targetObject);
targetList.add(targetObject);
}
}catch (Exception e){
logger.error("convert error ", e);
}
return targetList;
}
}
@@ -0,0 +1,56 @@
package com.weather.common.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日期处理
*
* @author 123
*/
public class DateUtils {
/** 时间格式(yyyy-MM-dd) */
public final static String DATE_PATTERN = "yyyy-MM-dd";
/** 时间格式(yyyy-MM-dd HH:mm:ss) */
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/**
* 日期格式化 日期格式为:yyyy-MM-dd
* @param date 日期
* @return 返回yyyy-MM-dd格式日期
*/
public static String format(Date date) {
return format(date, DATE_PATTERN);
}
/**
* 日期格式化 日期格式为:yyyy-MM-dd
* @param date 日期
* @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN
* @return 返回yyyy-MM-dd格式日期
*/
public static String format(Date date, String pattern) {
if (date != null) {
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
/**
* 日期解析
* @param date 日期
* @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN
* @return 返回Date
*/
public static Date parse(String date, String pattern) {
try {
return new SimpleDateFormat(pattern).parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
@@ -0,0 +1,57 @@
package com.weather.common.utils;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* Http
*
* @author 123
*/
public class HttpContextUtils {
public static HttpServletRequest getHttpServletRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if(requestAttributes == null){
return null;
}
return ((ServletRequestAttributes) requestAttributes).getRequest();
}
public static Map<String, String> getParameterMap(HttpServletRequest request) {
Enumeration<String> parameters = request.getParameterNames();
Map<String, String> params = new HashMap<>();
while (parameters.hasMoreElements()) {
String parameter = parameters.nextElement();
String value = request.getParameter(parameter);
if (StrUtil.isNotBlank(value)) {
params.put(parameter, value);
}
}
return params;
}
public static String getDomain(){
HttpServletRequest request = getHttpServletRequest();
StringBuffer url = request.getRequestURL();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
}
public static String getOrigin(){
HttpServletRequest request = getHttpServletRequest();
return request.getHeader(HttpHeaders.ORIGIN);
}
}
@@ -0,0 +1,52 @@
package com.weather.common.utils;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* IP地址
*
* @author 123
*/
public class IpUtils {
private static Logger logger = LoggerFactory.getLogger(IpUtils.class);
/**
* 获取IP地址
*
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String unknown = "unknown";
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StrUtil.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StrUtil.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StrUtil.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StrUtil.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StrUtil.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
logger.error("IPUtils ERROR ", e);
}
return ip;
}
}
@@ -0,0 +1,68 @@
package com.weather.common.utils;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
/**
* JSON 工具类
*
* @author 123
*/
public class JsonUtils {
private static final ObjectMapper objectMapper = new ObjectMapper();
public static String toJsonString(Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> T parseObject(String text, Class<T> clazz) {
if (StrUtil.isEmpty(text)) {
return null;
}
try {
return objectMapper.readValue(text, clazz);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
if (ArrayUtil.isEmpty(bytes)) {
return null;
}
try {
return objectMapper.readValue(bytes, clazz);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> T parseObject(String text, TypeReference<T> typeReference) {
try {
return objectMapper.readValue(text, typeReference);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> List<T> parseArray(String text, Class<T> clazz) {
if (StrUtil.isEmpty(text)) {
return new ArrayList<>();
}
try {
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,27 @@
package com.weather.common.utils;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
/**
* 国际化
*
* @author 123
* @since 1.0.0
*/
public class MessageUtils {
private static MessageSource messageSource;
static {
messageSource = (MessageSource)SpringContextUtils.getBean("messageSource");
}
public static String getMessage(int code){
return getMessage(code, new String[0]);
}
public static String getMessage(int code, String... params){
return messageSource.getMessage(code+"", params, LocaleContextHolder.getLocale());
}
}
@@ -0,0 +1,91 @@
package com.weather.common.utils;
import com.weather.common.exception.ErrorCode;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
/**
* 响应数据
*
* @author 123
* @since 1.0.0
*/
@Schema(title = "响应")
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 编码:0表示成功,其他值表示失败
*/
@Schema(title = "编码:0表示成功,其他值表示失败")
private int code = 0;
/**
* 消息内容
*/
@Schema(title = "消息内容")
private String msg = "success";
/**
* 响应数据
*/
@Schema(title = "响应数据")
private T data;
public Result<T> ok(T data) {
this.setData(data);
return this;
}
public boolean success(){
return code == 0;
}
public Result<T> error() {
this.code = ErrorCode.INTERNAL_SERVER_ERROR;
this.msg = MessageUtils.getMessage(this.code);
return this;
}
public Result<T> error(int code) {
this.code = code;
this.msg = MessageUtils.getMessage(this.code);
return this;
}
public Result<T> error(int code, String msg) {
this.code = code;
this.msg = msg;
return this;
}
public Result<T> error(String msg) {
this.code = ErrorCode.INTERNAL_SERVER_ERROR;
this.msg = msg;
return this;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
@@ -0,0 +1,49 @@
package com.weather.common.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring Context 工具类
*
* @author 123
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class<? extends Object> getType(String name) {
return applicationContext.getType(name);
}
}
@@ -0,0 +1,31 @@
package com.weather.common.utils;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 树节点,所有需要实现树节点的,都需要继承该类
*
* @author 123
* @since 1.0.0
*/
@Data
public class TreeNode<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 上级ID
*/
private Long pid;
/**
* 子节点列表
*/
private List<T> children = new ArrayList<>();
}
@@ -0,0 +1,74 @@
package com.weather.common.utils;
import com.weather.common.validator.AssertUtils;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 树形结构工具类,如:菜单、部门等
*
* @author 123
* @since 1.0.0
*/
public class TreeUtils {
/**
* 根据pid,构建树节点
*/
public static <T extends TreeNode> List<T> build(List<T> treeNodes, Long pid) {
//pid不能为空
AssertUtils.isNull(pid, "pid");
List<T> treeList = new ArrayList<>();
for(T treeNode : treeNodes) {
if (pid.equals(treeNode.getPid())) {
treeList.add(findChildren(treeNodes, treeNode));
}
}
return treeList;
}
/**
* 查找子节点
*/
private static <T extends TreeNode> T findChildren(List<T> treeNodes, T rootNode) {
for(T treeNode : treeNodes) {
if(rootNode.getId().equals(treeNode.getPid())) {
rootNode.getChildren().add(findChildren(treeNodes, treeNode));
}
}
return rootNode;
}
/**
* 构建树节点
*/
public static <T extends TreeNode> List<T> build(List<T> treeNodes) {
List<T> result = new ArrayList<>();
//list转map
Map<Long, T> nodeMap = new LinkedHashMap<>(treeNodes.size());
for(T treeNode : treeNodes){
nodeMap.put(treeNode.getId(), treeNode);
}
for(T node : nodeMap.values()) {
T parent = nodeMap.get(node.getPid());
if(parent != null && !(node.getId().equals(parent.getId()))){
parent.getChildren().add(node);
continue;
}
result.add(node);
}
return result;
}
}
@@ -0,0 +1,92 @@
package com.weather.common.validator;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import com.weather.common.exception.ErrorCode;
import com.weather.common.exception.CommonException;
import cn.hutool.core.util.StrUtil;
import java.util.List;
import java.util.Map;
/**
* 校验工具类
*
* @author 123
* @since 1.0.0
*/
public class AssertUtils {
public static void isBlank(String str, String... params) {
isBlank(str, ErrorCode.NOT_NULL, params);
}
public static void isBlank(String str, Integer code, String... params) {
if(code == null){
throw new CommonException(ErrorCode.NOT_NULL, "code");
}
if (StrUtil.isBlank(str)) {
throw new CommonException(code, params);
}
}
public static void isNull(Object object, String... params) {
isNull(object, ErrorCode.NOT_NULL, params);
}
public static void isNull(Object object, Integer code, String... params) {
if(code == null){
throw new CommonException(ErrorCode.NOT_NULL, "code");
}
if (object == null) {
throw new CommonException(code, params);
}
}
public static void isArrayEmpty(Object[] array, String... params) {
isArrayEmpty(array, ErrorCode.NOT_NULL, params);
}
public static void isArrayEmpty(Object[] array, Integer code, String... params) {
if(code == null){
throw new CommonException(ErrorCode.NOT_NULL, "code");
}
if(ArrayUtil.isEmpty(array)){
throw new CommonException(code, params);
}
}
public static void isListEmpty(List<?> list, String... params) {
isListEmpty(list, ErrorCode.NOT_NULL, params);
}
public static void isListEmpty(List<?> list, Integer code, String... params) {
if(code == null){
throw new CommonException(ErrorCode.NOT_NULL, "code");
}
if(CollUtil.isEmpty(list)){
throw new CommonException(code, params);
}
}
public static void isMapEmpty(Map map, String... params) {
isMapEmpty(map, ErrorCode.NOT_NULL, params);
}
public static void isMapEmpty(Map map, Integer code, String... params) {
if(code == null){
throw new CommonException(ErrorCode.NOT_NULL, "code");
}
if(MapUtil.isEmpty(map)){
throw new CommonException(code, params);
}
}
}
@@ -0,0 +1,51 @@
package com.weather.common.validator;
import com.weather.common.exception.CommonException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.beanvalidation.MessageSourceResourceBundleLocator;
import java.util.Locale;
import java.util.Set;
/**
* hibernate-validator校验工具类
* 参考文档:http://docs.jboss.org/hibernate/validator/6.0/reference/en-US/html_single/
*
* @author 123
* @since 1.0.0
*/
public class ValidatorUtils {
private static ResourceBundleMessageSource getMessageSource() {
ResourceBundleMessageSource bundleMessageSource = new ResourceBundleMessageSource();
bundleMessageSource.setDefaultEncoding("UTF-8");
bundleMessageSource.setBasenames("i18n/validation");
return bundleMessageSource;
}
/**
* 校验对象
* @param object 待校验对象
* @param groups 待校验的组
*/
public static void validateEntity(Object object, Class<?>... groups)
throws CommonException {
Locale.setDefault(LocaleContextHolder.getLocale());
Validator validator = Validation.byDefaultProvider().configure().messageInterpolator(
new ResourceBundleMessageInterpolator(new MessageSourceResourceBundleLocator(getMessageSource())))
.buildValidatorFactory().getValidator();
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
ConstraintViolation<Object> constraint = constraintViolations.iterator().next();
throw new CommonException(constraint.getMessage());
}
}
}
@@ -0,0 +1,13 @@
package com.weather.common.validator.group;
/**
* 新增 Group
*
* @author 123
* @since 1.0.0
*/
public interface AddGroup {
}
@@ -0,0 +1,13 @@
package com.weather.common.validator.group;
/**
* 默认 Group
*
* @author 123
* @since 1.0.0
*/
public interface DefaultGroup {
}
@@ -0,0 +1,17 @@
package com.weather.common.validator.group;
import jakarta.validation.GroupSequence;
/**
* 定义校验顺序,如果AddGroup组失败,则UpdateGroup组不会再校验
*
* @author 123
* @since 1.0.0
*/
@GroupSequence({AddGroup.class, UpdateGroup.class})
public interface Group {
}
@@ -0,0 +1,13 @@
package com.weather.common.validator.group;
/**
* 修改 Group
*
* @author 123
* @since 1.0.0
*/
public interface UpdateGroup {
}
@@ -0,0 +1,45 @@
package com.weather.common.xss;
import cn.hutool.core.util.StrUtil;
import com.weather.common.exception.ErrorCode;
import com.weather.common.exception.CommonException;
/**
* SQL过滤
*
* @author 123
*/
public class SqlFilter {
/**
* SQL注入过滤
*
* @param str 待验证的字符串
*/
public static String sqlInject(String str) {
if (StrUtil.isBlank(str)) {
return null;
}
//去掉'|"|;|\字符
str = StrUtil.replace(str, "'", "");
str = StrUtil.replace(str, "\"", "");
str = StrUtil.replace(str, ";", "");
str = StrUtil.replace(str, "\\", "");
//转换成小写
str = str.toLowerCase();
//非法字符
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
//判断是否包含非法字符
for (String keyword : keywords) {
if (str.contains(keyword)) {
throw new CommonException(ErrorCode.INVALID_SYMBOL);
}
}
return str;
}
}
@@ -0,0 +1,32 @@
package com.weather.common.xss;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* XSS过滤
* @author 123
*/
public class XssFilter implements Filter {
@Override
public void init(FilterConfig config) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
(HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
@Override
public void destroy() {
}
}
@@ -0,0 +1,148 @@
package com.weather.common.xss;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* XSS过滤处理
*
* @author 123
* @since 1.0.0
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
HttpServletRequest orgRequest;
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
orgRequest = request;
}
@Override
public ServletInputStream getInputStream() throws IOException {
//非json类型,直接返回
if(!checkContentTypeIsJson()){
return super.getInputStream();
}
//为空,直接返回
String json = IoUtil.readUtf8(super.getInputStream());
if (StrUtil.isBlank(json)) {
return super.getInputStream();
}
//xss过滤
json = xssEncode(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) {
}
@Override
public int read() {
return bis.read();
}
};
}
@Override
public String getParameter(String name) {
String value = super.getParameter(xssEncode(name));
if (StrUtil.isNotBlank(value)) {
value = xssEncode(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] parameters = super.getParameterValues(name);
if (parameters == null || parameters.length == 0) {
return null;
}
for (int i = 0; i < parameters.length; i++) {
parameters[i] = xssEncode(parameters[i]);
}
return parameters;
}
@Override
public Map<String,String[]> getParameterMap() {
Map<String,String[]> map = new LinkedHashMap<>();
Map<String,String[]> parameters = super.getParameterMap();
for (String key : parameters.keySet()) {
String[] values = parameters.get(key);
for (int i = 0; i < values.length; i++) {
values[i] = xssEncode(values[i]);
}
map.put(key, values);
}
return map;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (StrUtil.isNotBlank(value)) {
value = xssEncode(value);
}
return value;
}
private String xssEncode(String input) {
return XssUtils.filter(input);
}
/**
* 获取最原始的request
*/
public HttpServletRequest getOrgRequest() {
return orgRequest;
}
/**
* 获取最原始的request
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
if (request instanceof XssHttpServletRequestWrapper) {
return ((XssHttpServletRequestWrapper) request).getOrgRequest();
}
return request;
}
/**
* 判断是否是json请求,以前缀的方式
*/
private boolean checkContentTypeIsJson()
{
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
return StrUtil.startWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
}
}
@@ -0,0 +1,72 @@
package com.weather.common.xss;
import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;
/**
* XSS过滤工具类
*
* @author 123
* @since 1.0.0
*/
public class XssUtils extends Safelist {
/**
* XSS过滤
*/
public static String filter(String html){
return Jsoup.clean(html, xssWhitelist());
}
/**
* XSS过滤白名单
*/
private static Safelist xssWhitelist(){
return new Safelist()
//支持的标签
.addTags("a", "b", "blockquote", "br", "caption", "cite", "code", "col", "colgroup", "dd", "div", "dl",
"dt", "em", "h1", "h2", "h3", "h4", "h5", "h6", "i", "img", "li", "ol", "p", "pre", "q", "small",
"strike", "strong","sub", "sup", "table", "tbody", "td","tfoot", "th", "thead", "tr", "u","ul",
"embed","object","param","span")
//支持的标签属性
.addAttributes("a", "href", "class", "style", "target", "rel", "nofollow")
.addAttributes("blockquote", "cite")
.addAttributes("code", "class", "style")
.addAttributes("col", "span", "width")
.addAttributes("colgroup", "span", "width")
.addAttributes("img", "align", "alt", "height", "src", "title", "width", "class", "style")
.addAttributes("ol", "start", "type")
.addAttributes("q", "cite")
.addAttributes("table", "summary", "width", "class", "style")
.addAttributes("tr", "abbr", "axis", "colspan", "rowspan", "width", "style")
.addAttributes("td", "abbr", "axis", "colspan", "rowspan", "width", "style")
.addAttributes("th", "abbr", "axis", "colspan", "rowspan", "scope","width", "style")
.addAttributes("ul", "type", "style")
.addAttributes("pre", "class", "style")
.addAttributes("div", "class", "id", "style")
.addAttributes("embed", "src", "wmode", "flashvars", "pluginspage", "allowFullScreen", "allowfullscreen",
"quality", "width", "height", "align", "allowScriptAccess", "allowscriptaccess", "allownetworking", "type")
.addAttributes("object", "type", "id", "name", "data", "width", "height", "style", "classid", "codebase")
.addAttributes("param", "name", "value")
.addAttributes("span", "class", "style")
//标签属性对应的协议
.addProtocols("a", "href", "ftp", "http", "https", "mailto")
.addProtocols("img", "src", "http", "https")
.addProtocols("blockquote", "cite", "http", "https")
.addProtocols("cite", "cite", "http", "https")
.addProtocols("q", "cite", "http", "https")
.addProtocols("embed", "src", "http", "https");
}
public static void main(String[] args) {
StringBuilder html = new StringBuilder();
html.append("<a href=\"https://www.weather.cn\" target=\"_blank\">人人开源</a>");
System.out.println(filter(html.toString()));
}
}
@@ -0,0 +1,26 @@
#Default
500=\u670D\u52A1\u5668\u5185\u90E8\u5F02\u5E38
401=\u672A\u6388\u6743
10001={0}\u4E0D\u80FD\u4E3A\u7A7A
10002=\u6570\u636E\u5E93\u4E2D\u5DF2\u5B58\u5728\u8BE5\u8BB0\u5F55
10003=\u83B7\u53D6\u53C2\u6570\u5931\u8D25
10004=\u8D26\u53F7\u6216\u5BC6\u7801\u9519\u8BEF
10005=\u8D26\u53F7\u5DF2\u88AB\u505C\u7528
10006=\u552F\u4E00\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A
10007=\u9A8C\u8BC1\u7801\u4E0D\u6B63\u786E
10008=\u5148\u5220\u9664\u5B50\u83DC\u5355\u6216\u6309\u94AE
10009=\u539F\u5BC6\u7801\u4E0D\u6B63\u786E
10010=\u8D26\u53F7\u4E0D\u5B58\u5728
10011=\u4E0A\u7EA7\u90E8\u95E8\u9009\u62E9\u9519\u8BEF
10012=\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u4E3A\u81EA\u8EAB
10013=\u6570\u636E\u6743\u9650\u63A5\u53E3\uFF0C\u53EA\u80FD\u662FMap\u7C7B\u578B\u53C2\u6570
10014=\u8BF7\u5148\u5220\u9664\u4E0B\u7EA7\u90E8\u95E8
10015=\u8BF7\u5148\u5220\u9664\u90E8\u95E8\u4E0B\u7684\u7528\u6237
10019=\u8BF7\u4E0A\u4F20\u6587\u4EF6
10020=token\u4E0D\u80FD\u4E3A\u7A7A
10021=token\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
10022=\u8D26\u53F7\u5DF2\u88AB\u9501\u5B9A
10024=\u4E0A\u4F20\u6587\u4EF6\u5931\u8D25{0}
10027=Redis\u670D\u52A1\u5F02\u5E38
10028=\u5B9A\u65F6\u4EFB\u52A1\u5931\u8D25
10029=\u4E0D\u80FD\u5305\u542B\u975E\u6CD5\u5B57\u7B26
@@ -0,0 +1,67 @@
#\u7B80\u4F53\u4E2D\u6587
id.require=ID\u4E0D\u80FD\u4E3A\u7A7A
id.null=ID\u5FC5\u987B\u4E3A\u7A7A
pid.require=\u4E0A\u7EA7ID\uFF0C\u4E0D\u80FD\u4E3A\u7A7A
sort.number=\u6392\u5E8F\u503C\u4E0D\u80FD\u5C0F\u4E8E0
sysparams.paramcode.require=\u53C2\u6570\u7F16\u7801\u4E0D\u80FD\u4E3A\u7A7A
sysparams.paramvalue.require=\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A
sysuser.username.require=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
sysuser.password.require=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
sysuser.realname.require=\u59D3\u540D\u4E0D\u80FD\u4E3A\u7A7A
sysuser.gender.range=\u6027\u522B\u53D6\u503C\u8303\u56F40~2
sysuser.email.require=\u90AE\u7BB1\u4E0D\u80FD\u4E3A\u7A7A
sysuser.email.error=\u90AE\u7BB1\u683C\u5F0F\u4E0D\u6B63\u786E
sysuser.mobile.require=\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A
sysuser.deptId.require=\u90E8\u95E8\u4E0D\u80FD\u4E3A\u7A7A
sysuser.superadmin.range=\u8D85\u7EA7\u7BA1\u7406\u5458\u53D6\u503C\u8303\u56F40~1
sysuser.status.range=\u72B6\u6001\u53D6\u503C\u8303\u56F40~1
sysuser.captcha.require=\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A
sysuser.uuid.require=\u552F\u4E00\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A
sysmenu.pid.require=\u8BF7\u9009\u62E9\u4E0A\u7EA7\u83DC\u5355
sysmenu.name.require=\u83DC\u5355\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
sysmenu.type.range=\u83DC\u5355\u7C7B\u578B\u53D6\u503C\u8303\u56F40~1
sysdept.pid.require=\u8BF7\u9009\u62E9\u4E0A\u7EA7\u90E8\u95E8
sysdept.name.require=\u90E8\u95E8\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
sysrole.name.require=\u89D2\u8272\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
sysdict.type.require=\u5B57\u5178\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
sysdict.name.require=\u5B57\u5178\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
sysdict.label.require=\u5B57\u5178\u6807\u7B7E\u4E0D\u80FD\u4E3A\u7A7A
schedule.status.range=\u72B6\u6001\u53D6\u503C\u8303\u56F40~1
schedule.cron.require=cron\u8868\u8FBE\u5F0F\u4E0D\u80FD\u4E3A\u7A7A
schedule.bean.require=bean\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
oss.type.range=\u7C7B\u578B\u53D6\u503C\u8303\u56F41~3
aliyun.accesskeyid.require=\u963F\u91CC\u4E91AccessKeyId\u4E0D\u80FD\u4E3A\u7A7A
aliyun.accesskeysecret.require=\u963F\u91CC\u4E91AccessKeySecret\u4E0D\u80FD\u4E3A\u7A7A
aliyun.signname.require=\u963F\u91CC\u4E91\u77ED\u4FE1\u7B7E\u540D\u4E0D\u80FD\u4E3A\u7A7A
aliyun.templatecode.require=\u963F\u91CC\u4E91\u77ED\u4FE1\u6A21\u677F\u4E0D\u80FD\u4E3A\u7A7A
aliyun.domain.require=\u963F\u91CC\u4E91\u7ED1\u5B9A\u7684\u57DF\u540D\u4E0D\u80FD\u4E3A\u7A7A
aliyun.domain.url=\u963F\u91CC\u4E91\u7ED1\u5B9A\u7684\u57DF\u540D\u683C\u5F0F\u4E0D\u6B63\u786E
aliyun.endPoint.require=\u963F\u91CC\u4E91EndPoint\u4E0D\u80FD\u4E3A\u7A7A
aliyun.bucketname.require=\u963F\u91CC\u4E91BucketName\u4E0D\u80FD\u4E3A\u7A7A
qcloud.appid.require=\u817E\u8BAF\u4E91AppId\u4E0D\u80FD\u4E3A\u7A7A
qcloud.appkey.require=\u817E\u8BAF\u4E91AppKey\u4E0D\u80FD\u4E3A\u7A7A
qcloud.secretId.require=\u817E\u8BAF\u4E91SecretId\u4E0D\u80FD\u4E3A\u7A7A
qcloud.secretkey.require=\u817E\u8BAF\u4E91SecretKey\u4E0D\u80FD\u4E3A\u7A7A
qcloud.signname.require=\u817E\u8BAF\u4E91\u77ED\u4FE1\u7B7E\u540D\u4E0D\u80FD\u4E3A\u7A7A
qcloud.templateid.require=\u817E\u8BAF\u4E91\u77ED\u4FE1\u6A21\u677FID\u4E0D\u80FD\u4E3A\u7A7A
qcloud.domain.require=\u817E\u8BAF\u4E91\u7ED1\u5B9A\u7684\u57DF\u540D\u4E0D\u80FD\u4E3A\u7A7A
qcloud.domain.url=\u817E\u8BAF\u4E91\u7ED1\u5B9A\u7684\u57DF\u540D\u683C\u5F0F\u4E0D\u6B63\u786E
qcloud.bucketname.require=\u817E\u8BAF\u4E91BucketName\u4E0D\u80FD\u4E3A\u7A7A
qcloud.region.require=\u6240\u5C5E\u5730\u533A\u4E0D\u80FD\u4E3A\u7A7A
qiniu.domain.require=\u4E03\u725B\u7ED1\u5B9A\u7684\u57DF\u540D\u4E0D\u80FD\u4E3A\u7A7A
qiniu.domain.url=\u4E03\u725B\u7ED1\u5B9A\u7684\u57DF\u540D\u683C\u5F0F\u4E0D\u6B63\u786E
qiniu.accesskey.require=\u4E03\u725BAccessKey\u4E0D\u80FD\u4E3A\u7A7A
qiniu.secretkey.require=\u4E03\u725BSecretKey\u4E0D\u80FD\u4E3A\u7A7A
qiniu.bucketname.require=\u4E03\u725B\u7A7A\u95F4\u540D\u4E0D\u80FD\u4E3A\u7A7A
qiniu.templateId.require=\u4E03\u725B\u6A21\u677FID\u4E0D\u80FD\u4E3A\u7A7A