1.0版本完成
This commit is contained in:
35
yshop-common/src/main/java/co/yixiang/annotation/Limit.java
Normal file
35
yshop-common/src/main/java/co/yixiang/annotation/Limit.java
Normal file
@ -0,0 +1,35 @@
|
||||
package co.yixiang.annotation;
|
||||
|
||||
import co.yixiang.aspect.LimitType;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author jacky
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Limit {
|
||||
|
||||
// 资源名称,用于描述接口功能
|
||||
String name() default "";
|
||||
|
||||
// 资源 key
|
||||
String key() default "";
|
||||
|
||||
// key prefix
|
||||
String prefix() default "";
|
||||
|
||||
// 时间的,单位秒
|
||||
int period();
|
||||
|
||||
// 限制访问次数
|
||||
int count();
|
||||
|
||||
// 限制类型
|
||||
LimitType limitType() default LimitType.CUSTOMER;
|
||||
|
||||
}
|
||||
70
yshop-common/src/main/java/co/yixiang/annotation/Query.java
Normal file
70
yshop-common/src/main/java/co/yixiang/annotation/Query.java
Normal file
@ -0,0 +1,70 @@
|
||||
package co.yixiang.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-6-4 13:52:30
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Query {
|
||||
|
||||
/** Dong ZhaoYang 2017/8/7 基本对象的属性名 */
|
||||
String propName() default "";
|
||||
/** Dong ZhaoYang 2017/8/7 查询方式 */
|
||||
Type type() default Type.EQUAL;
|
||||
|
||||
/**
|
||||
* 连接查询的属性名,如User类中的dept
|
||||
* @return
|
||||
*/
|
||||
String joinName() default "";
|
||||
|
||||
/**
|
||||
* 默认左连接
|
||||
* @return
|
||||
*/
|
||||
Join join() default Join.LEFT;
|
||||
|
||||
/**
|
||||
* 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username")
|
||||
* @return
|
||||
*/
|
||||
String blurry() default "";
|
||||
|
||||
enum Type {
|
||||
/** jie 2019/6/4 相等 */
|
||||
EQUAL
|
||||
/** Dong ZhaoYang 2017/8/7 大于等于 */
|
||||
, GREATER_THAN
|
||||
/** Dong ZhaoYang 2017/8/7 小于等于 */
|
||||
, LESS_THAN
|
||||
/** Dong ZhaoYang 2017/8/7 中模糊查询 */
|
||||
, INNER_LIKE
|
||||
/** Dong ZhaoYang 2017/8/7 左模糊查询 */
|
||||
, LEFT_LIKE
|
||||
/** Dong ZhaoYang 2017/8/7 右模糊查询 */
|
||||
, RIGHT_LIKE
|
||||
/** Dong ZhaoYang 2017/8/7 小于 */
|
||||
, LESS_THAN_NQ
|
||||
//** jie 2019/6/4 包含 */
|
||||
, IN
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询
|
||||
*/
|
||||
enum Join {
|
||||
/** jie 2019-6-4 13:18:30 左连接 */
|
||||
LEFT
|
||||
/** jie 2019-6-4 13:18:30 右连接 */
|
||||
, RIGHT
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
package co.yixiang.aspect;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import co.yixiang.annotation.Limit;
|
||||
import co.yixiang.exception.BadRequestException;
|
||||
import co.yixiang.utils.RequestHolder;
|
||||
import co.yixiang.utils.StringUtils;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class LimitAspect {
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class);
|
||||
|
||||
|
||||
@Pointcut("@annotation(co.yixiang.annotation.Limit)")
|
||||
public void pointcut() {
|
||||
}
|
||||
|
||||
@Around("pointcut()")
|
||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method signatureMethod = signature.getMethod();
|
||||
Limit limit = signatureMethod.getAnnotation(Limit.class);
|
||||
LimitType limitType = limit.limitType();
|
||||
String key = limit.key();
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
switch (limitType) {
|
||||
case IP:
|
||||
key = StringUtils.getIP(request);
|
||||
break;
|
||||
default:
|
||||
key = signatureMethod.getName();
|
||||
}
|
||||
}
|
||||
|
||||
ImmutableList keys = ImmutableList.of(StringUtils.join(limit.prefix(), "_", key, "_", request.getRequestURI().replaceAll("/","_")));
|
||||
|
||||
String luaScript = buildLuaScript();
|
||||
RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);
|
||||
Number count = (Number) redisTemplate.execute(redisScript, keys, limit.count(), limit.period());
|
||||
if (null != count && count.intValue() <= limit.count()) {
|
||||
logger.info("第{}次访问key为 {},描述为 [{}] 的接口", count, keys, limit.name());
|
||||
return joinPoint.proceed();
|
||||
} else {
|
||||
throw new BadRequestException("访问次数受限制");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流脚本
|
||||
*/
|
||||
private String buildLuaScript() {
|
||||
return "local c" +
|
||||
"\nc = redis.call('get',KEYS[1])" +
|
||||
"\nif c and tonumber(c) > tonumber(ARGV[1]) then" +
|
||||
"\nreturn c;" +
|
||||
"\nend" +
|
||||
"\nc = redis.call('incr',KEYS[1])" +
|
||||
"\nif tonumber(c) == 1 then" +
|
||||
"\nredis.call('expire',KEYS[1],ARGV[2])" +
|
||||
"\nend" +
|
||||
"\nreturn c;";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package co.yixiang.aspect;
|
||||
|
||||
public enum LimitType {
|
||||
CUSTOMER,
|
||||
// by ip addr
|
||||
IP;
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package co.yixiang.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
* 统一异常处理
|
||||
*/
|
||||
@Getter
|
||||
public class BadRequestException extends RuntimeException{
|
||||
|
||||
private Integer status = BAD_REQUEST.value();
|
||||
|
||||
public BadRequestException(String msg){
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public BadRequestException(HttpStatus status,String msg){
|
||||
super(msg);
|
||||
this.status = status.value();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package co.yixiang.exception;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public class EntityExistException extends RuntimeException {
|
||||
|
||||
public EntityExistException(Class clazz, Object... saveBodyParamsMap) {
|
||||
super(EntityExistException.generateMessage(clazz.getSimpleName(), toMap(String.class, String.class, saveBodyParamsMap)));
|
||||
}
|
||||
|
||||
private static String generateMessage(String entity, Map<String, String> saveBodyParams) {
|
||||
return StringUtils.capitalize(entity) +
|
||||
" 已存在 " +
|
||||
saveBodyParams;
|
||||
}
|
||||
|
||||
private static <K, V> Map<K, V> toMap(
|
||||
Class<K> keyType, Class<V> valueType, Object... entries) {
|
||||
if (entries.length % 2 == 1)
|
||||
throw new IllegalArgumentException("Invalid entries");
|
||||
return IntStream.range(0, entries.length / 2).map(i -> i * 2)
|
||||
.collect(HashMap::new,
|
||||
(m, i) -> m.put(keyType.cast(entries[i]), valueType.cast(entries[i + 1])),
|
||||
Map::putAll);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package co.yixiang.exception;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public class EntityNotFoundException extends RuntimeException {
|
||||
|
||||
public EntityNotFoundException(Class clazz, Object... searchParamsMap) {
|
||||
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), toMap(String.class, String.class, searchParamsMap)));
|
||||
}
|
||||
|
||||
private static String generateMessage(String entity, Map<String, String> searchParams) {
|
||||
return StringUtils.capitalize(entity) +
|
||||
" 不存在 " +
|
||||
searchParams;
|
||||
}
|
||||
|
||||
private static <K, V> Map<K, V> toMap(
|
||||
Class<K> keyType, Class<V> valueType, Object... entries) {
|
||||
if (entries.length % 2 == 1)
|
||||
throw new IllegalArgumentException("Invalid entries");
|
||||
return IntStream.range(0, entries.length / 2).map(i -> i * 2)
|
||||
.collect(HashMap::new,
|
||||
(m, i) -> m.put(keyType.cast(entries[i]), valueType.cast(entries[i + 1])),
|
||||
Map::putAll);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package co.yixiang.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
* 统一异常处理
|
||||
*/
|
||||
@Getter
|
||||
public class ErrorRequestException extends RuntimeException{
|
||||
|
||||
private Integer status = BAD_REQUEST.value();
|
||||
|
||||
public ErrorRequestException(String msg){
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public ErrorRequestException(HttpStatus status, String msg){
|
||||
super(msg);
|
||||
this.status = status.value();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package co.yixiang.exception.handler;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author hupeng
|
||||
* @since 2019-10-02
|
||||
*/
|
||||
@Data
|
||||
class ApiErr {
|
||||
|
||||
private Integer status;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime timestamp;
|
||||
private String msg;
|
||||
|
||||
private ApiErr() {
|
||||
timestamp = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public ApiErr(Integer status, String message) {
|
||||
this();
|
||||
this.status = status;
|
||||
this.msg = message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package co.yixiang.exception.handler;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
@Data
|
||||
class ApiError {
|
||||
|
||||
private Integer status;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime timestamp;
|
||||
private String message;
|
||||
|
||||
private ApiError() {
|
||||
timestamp = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public ApiError(Integer status,String message) {
|
||||
this();
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,136 @@
|
||||
package co.yixiang.exception.handler;
|
||||
|
||||
import co.yixiang.exception.BadRequestException;
|
||||
import co.yixiang.exception.EntityNotFoundException;
|
||||
import co.yixiang.exception.ErrorRequestException;
|
||||
import co.yixiang.utils.ThrowableUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import co.yixiang.exception.EntityExistException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import static org.springframework.http.HttpStatus.*;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 处理所有不可知的异常
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(Throwable.class)
|
||||
public ResponseEntity handleException(Throwable e){
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage());
|
||||
return buildResponseEntity(apiError);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 接口无权访问异常AccessDeniedException
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public ResponseEntity handleAccessDeniedException(AccessDeniedException e){
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
ApiError apiError = new ApiError(FORBIDDEN.value(),e.getMessage());
|
||||
return buildResponseEntity(apiError);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(value = BadRequestException.class)
|
||||
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
ApiError apiError = new ApiError(e.getStatus(),e.getMessage());
|
||||
return buildResponseEntity(apiError);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(value = ErrorRequestException.class)
|
||||
public ResponseEntity<ApiErr> errorRequestException(ErrorRequestException e) {
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
ApiErr apiError = new ApiErr(e.getStatus(),e.getMessage());
|
||||
return buildResponseEntity2(apiError);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 EntityExist
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(value = EntityExistException.class)
|
||||
public ResponseEntity<ApiError> entityExistException(EntityExistException e) {
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage());
|
||||
return buildResponseEntity(apiError);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 EntityNotFound
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(value = EntityNotFoundException.class)
|
||||
public ResponseEntity<ApiError> entityNotFoundException(EntityNotFoundException e) {
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
ApiError apiError = new ApiError(NOT_FOUND.value(),e.getMessage());
|
||||
return buildResponseEntity(apiError);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理所有接口数据验证异常
|
||||
* @param e
|
||||
* @returns
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
String[] str = e.getBindingResult().getAllErrors().get(0).getCodes()[1].split("\\.");
|
||||
StringBuffer msg = new StringBuffer(str[1]+":");
|
||||
msg.append(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||
ApiError apiError = new ApiError(BAD_REQUEST.value(),msg.toString());
|
||||
return buildResponseEntity(apiError);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一返回
|
||||
* @param apiError
|
||||
* @return
|
||||
*/
|
||||
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
|
||||
return new ResponseEntity(apiError, HttpStatus.valueOf(apiError.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一返回
|
||||
* @param apiError
|
||||
* @return
|
||||
*/
|
||||
private ResponseEntity<ApiErr> buildResponseEntity2(ApiErr apiError) {
|
||||
return new ResponseEntity(apiError, HttpStatus.valueOf(apiError.getStatus()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package co.yixiang.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public interface EntityMapper<D, E> {
|
||||
|
||||
/**
|
||||
* DTO转Entity
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
E toEntity(D dto);
|
||||
|
||||
/**
|
||||
* Entity转DTO
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
D toDto(E entity);
|
||||
|
||||
/**
|
||||
* DTO集合转Entity集合
|
||||
* @param dtoList
|
||||
* @return
|
||||
*/
|
||||
List <E> toEntity(List<D> dtoList);
|
||||
|
||||
/**
|
||||
* Entity集合转DTO集合
|
||||
* @param entityList
|
||||
* @return
|
||||
*/
|
||||
List <D> toDto(List<E> entityList);
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package co.yixiang.redis;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.SerializationException;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Value 序列化
|
||||
*
|
||||
* @author /
|
||||
* @param <T>
|
||||
*/
|
||||
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
|
||||
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
private Class<T> clazz;
|
||||
|
||||
public FastJsonRedisSerializer(Class<T> clazz) {
|
||||
super();
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(T t) throws SerializationException {
|
||||
if (t == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(byte[] bytes) throws SerializationException {
|
||||
if (bytes == null || bytes.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
String str = new String(bytes, DEFAULT_CHARSET);
|
||||
return (T) JSON.parseObject(str, clazz);
|
||||
}
|
||||
|
||||
}
|
||||
126
yshop-common/src/main/java/co/yixiang/redis/RedisConfig.java
Normal file
126
yshop-common/src/main/java/co/yixiang/redis/RedisConfig.java
Normal file
@ -0,0 +1,126 @@
|
||||
package co.yixiang.redis;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
// 自动配置
|
||||
@ConditionalOnClass(RedisOperations.class)
|
||||
@EnableConfigurationProperties(RedisProperties.class)
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
/**
|
||||
* 设置 redis 数据默认过期时间,默认1天
|
||||
* 设置@cacheable 序列化方式
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public RedisCacheConfiguration redisCacheConfiguration(){
|
||||
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
||||
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
|
||||
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofDays(1));
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@Bean(name = "redisTemplate")
|
||||
@ConditionalOnMissingBean(name = "redisTemplate")
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
//序列化
|
||||
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
|
||||
// value值的序列化采用fastJsonRedisSerializer
|
||||
template.setValueSerializer(fastJsonRedisSerializer);
|
||||
template.setHashValueSerializer(fastJsonRedisSerializer);
|
||||
|
||||
// 全局开启AutoType,不建议使用
|
||||
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
||||
// 建议使用这种方式,小范围指定白名单
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.modules.order.entity");
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.modules.order.web.dto");
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.modules.system.service.dto");
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.service.dto");
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.modules.system.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.modules.quartz.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.modules.monitor.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("co.yixiang.modules.security.security");
|
||||
// key的序列化采用StringRedisSerializer
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setConnectionFactory(redisConnectionFactory);
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义缓存key生成策略,默认将使用该策略
|
||||
* 使用方法 @Cacheable
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@Override
|
||||
public KeyGenerator keyGenerator() {
|
||||
return (target, method, params) -> {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(target.getClass().getName());
|
||||
sb.append(method.getName());
|
||||
for (Object obj : params) {
|
||||
sb.append(JSON.toJSONString(obj).hashCode());
|
||||
}
|
||||
return sb.toString();
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public CacheErrorHandler errorHandler() {
|
||||
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
||||
log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
|
||||
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
|
||||
@Override
|
||||
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
|
||||
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheClearError(RuntimeException e, Cache cache) {
|
||||
log.error("Redis occur handleCacheClearError:", e);
|
||||
}
|
||||
};
|
||||
return cacheErrorHandler;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package co.yixiang.redis;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 重写序列化器
|
||||
*
|
||||
* @author /
|
||||
*/
|
||||
public class StringRedisSerializer implements RedisSerializer<Object> {
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
private final String target = "\"";
|
||||
|
||||
private final String replacement = "";
|
||||
|
||||
public StringRedisSerializer() {
|
||||
this(Charset.forName("UTF8"));
|
||||
}
|
||||
|
||||
public StringRedisSerializer(Charset charset) {
|
||||
Assert.notNull(charset, "Charset must not be null!");
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deserialize(byte[] bytes) {
|
||||
return (bytes == null ? null : new String(bytes, charset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Object object) {
|
||||
String string = JSON.toJSONString(object);
|
||||
if (string == null) {
|
||||
return null;
|
||||
}
|
||||
string = string.replace(target, replacement);
|
||||
return string.getBytes(charset);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package co.yixiang.swagger2;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.ParameterBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.schema.ModelRef;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.service.Parameter;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* api页面 /swagger-ui.html
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
|
||||
//@Configuration
|
||||
//@EnableSwagger2
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Value("${jwt.header}")
|
||||
private String tokenHeader;
|
||||
|
||||
@Value("${swagger.enabled}")
|
||||
private Boolean enabled;
|
||||
|
||||
@Bean
|
||||
public Docket createRestApi() {
|
||||
ParameterBuilder ticketPar = new ParameterBuilder();
|
||||
List<Parameter> pars = new ArrayList<Parameter>();
|
||||
ticketPar.name(tokenHeader).description("token")
|
||||
.modelRef(new ModelRef("string"))
|
||||
.parameterType("header")
|
||||
.defaultValue("Bearer ")
|
||||
.required(true)
|
||||
.build();
|
||||
pars.add(ticketPar.build());
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.enable(enabled)
|
||||
.apiInfo(apiInfo())
|
||||
.select()
|
||||
.paths(Predicates.not(PathSelectors.regex("/error.*")))
|
||||
.build()
|
||||
.globalOperationParameters(pars);
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.title("eladmin 接口文档")
|
||||
.version("2.1")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
package co.yixiang.swagger2;
|
||||
43
yshop-common/src/main/java/co/yixiang/utils/CateDTO.java
Normal file
43
yshop-common/src/main/java/co/yixiang/utils/CateDTO.java
Normal file
@ -0,0 +1,43 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 商城商品分类
|
||||
* </p>
|
||||
*
|
||||
* @author hupeng
|
||||
* @since 2019-09-08
|
||||
*/
|
||||
@Data
|
||||
public class CateDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
private Long id;
|
||||
/**
|
||||
* 上级分类编号
|
||||
*/
|
||||
private Long pid;
|
||||
|
||||
/**
|
||||
* 商品分类名称
|
||||
*/
|
||||
private String cateName;
|
||||
|
||||
/**
|
||||
* 缩略图url
|
||||
*/
|
||||
private String pic;
|
||||
|
||||
private List<CateDTO> children = new ArrayList<>();
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
/**
|
||||
* 常用静态常量
|
||||
* @author Zheng Jie
|
||||
* @date 2018-12-26
|
||||
*/
|
||||
public class ElAdminConstant {
|
||||
|
||||
public static final String RESET_PASS = "重置密码";
|
||||
|
||||
public static final String RESET_MAIL = "重置邮箱";
|
||||
|
||||
/**
|
||||
* 用于IP定位转换
|
||||
*/
|
||||
public static final String REGION = "内网IP|内网IP";
|
||||
|
||||
/**
|
||||
* 常用接口
|
||||
*/
|
||||
public static class Url{
|
||||
public static final String SM_MS_URL = "https://sm.ms/api/upload";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import org.springframework.util.DigestUtils;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
/**
|
||||
* 加密
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public class EncryptUtils {
|
||||
|
||||
private static String strKey = "Passw0rd", strParam = "Passw0rd";
|
||||
|
||||
/**
|
||||
* 对称加密
|
||||
* @param source
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String desEncrypt(String source) throws Exception {
|
||||
if (source == null || source.length() == 0){
|
||||
return null;
|
||||
}
|
||||
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
|
||||
DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes("UTF-8"));
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
|
||||
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
|
||||
IvParameterSpec iv = new IvParameterSpec(strParam.getBytes("UTF-8"));
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
|
||||
return byte2hex(
|
||||
cipher.doFinal(source.getBytes("UTF-8"))).toUpperCase();
|
||||
}
|
||||
|
||||
public static String byte2hex(byte[] inStr) {
|
||||
String stmp;
|
||||
StringBuffer out = new StringBuffer(inStr.length * 2);
|
||||
for (int n = 0; n < inStr.length; n++) {
|
||||
stmp = Integer.toHexString(inStr[n] & 0xFF);
|
||||
if (stmp.length() == 1) {
|
||||
// 如果是0至F的单位字符串,则添加0
|
||||
out.append("0" + stmp);
|
||||
} else {
|
||||
out.append(stmp);
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
|
||||
public static byte[] hex2byte(byte[] b) {
|
||||
if ((b.length % 2) != 0){
|
||||
throw new IllegalArgumentException("长度不是偶数");
|
||||
}
|
||||
byte[] b2 = new byte[b.length / 2];
|
||||
for (int n = 0; n < b.length; n += 2) {
|
||||
String item = new String(b, n, 2);
|
||||
b2[n / 2] = (byte) Integer.parseInt(item, 16);
|
||||
}
|
||||
return b2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对称解密
|
||||
* @param source
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String desDecrypt(String source) throws Exception {
|
||||
if (source == null || source.length() == 0){
|
||||
return null;
|
||||
}
|
||||
byte[] src = hex2byte(source.getBytes());
|
||||
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
|
||||
DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes("UTF-8"));
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
|
||||
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
|
||||
IvParameterSpec iv = new IvParameterSpec(strParam.getBytes("UTF-8"));
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
|
||||
byte[] retByte = cipher.doFinal(src);
|
||||
return new String(retByte);
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码加密
|
||||
* @param password
|
||||
* @return
|
||||
*/
|
||||
public static String encryptPassword(String password){
|
||||
return DigestUtils.md5DigestAsHex(password.getBytes());
|
||||
}
|
||||
}
|
||||
244
yshop-common/src/main/java/co/yixiang/utils/FileUtil.java
Normal file
244
yshop-common/src/main/java/co/yixiang/utils/FileUtil.java
Normal file
@ -0,0 +1,244 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.poi.excel.BigExcelWriter;
|
||||
import cn.hutool.poi.excel.ExcelUtil;
|
||||
import co.yixiang.exception.BadRequestException;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* File工具类,扩展 hutool 工具包
|
||||
* @author Zheng Jie
|
||||
* @date 2018-12-27
|
||||
*/
|
||||
public class FileUtil extends cn.hutool.core.io.FileUtil {
|
||||
|
||||
/**
|
||||
* 定义GB的计算常量
|
||||
*/
|
||||
private static final int GB = 1024 * 1024 * 1024;
|
||||
/**
|
||||
* 定义MB的计算常量
|
||||
*/
|
||||
private static final int MB = 1024 * 1024;
|
||||
/**
|
||||
* 定义KB的计算常量
|
||||
*/
|
||||
private static final int KB = 1024;
|
||||
|
||||
/**
|
||||
* 格式化小数
|
||||
*/
|
||||
private static final DecimalFormat DF = new DecimalFormat("0.00");
|
||||
|
||||
/**
|
||||
* MultipartFile转File
|
||||
* @param multipartFile
|
||||
* @return
|
||||
*/
|
||||
public static File toFile(MultipartFile multipartFile){
|
||||
// 获取文件名
|
||||
String fileName = multipartFile.getOriginalFilename();
|
||||
// 获取文件后缀
|
||||
String prefix="."+getExtensionName(fileName);
|
||||
File file = null;
|
||||
try {
|
||||
// 用uuid作为文件名,防止生成的临时文件重复
|
||||
file = File.createTempFile(IdUtil.simpleUUID(), prefix);
|
||||
// MultipartFile to File
|
||||
multipartFile.transferTo(file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param files
|
||||
*/
|
||||
public static void deleteFile(File... files) {
|
||||
for (File file : files) {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
* @param filename
|
||||
* @return
|
||||
*/
|
||||
public static String getExtensionName(String filename) {
|
||||
if ((filename != null) && (filename.length() > 0)) {
|
||||
int dot = filename.lastIndexOf('.');
|
||||
if ((dot >-1) && (dot < (filename.length() - 1))) {
|
||||
return filename.substring(dot + 1);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Java文件操作 获取不带扩展名的文件名
|
||||
* @param filename
|
||||
* @return
|
||||
*/
|
||||
public static String getFileNameNoEx(String filename) {
|
||||
if ((filename != null) && (filename.length() > 0)) {
|
||||
int dot = filename.lastIndexOf('.');
|
||||
if ((dot >-1) && (dot < (filename.length()))) {
|
||||
return filename.substring(0, dot);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件大小转换
|
||||
* @param size
|
||||
* @return
|
||||
*/
|
||||
public static String getSize(long size){
|
||||
String resultSize = "";
|
||||
if (size / GB >= 1) {
|
||||
//如果当前Byte的值大于等于1GB
|
||||
resultSize = DF.format(size / (float) GB) + "GB ";
|
||||
} else if (size / MB >= 1) {
|
||||
//如果当前Byte的值大于等于1MB
|
||||
resultSize = DF.format(size / (float) MB) + "MB ";
|
||||
} else if (size / KB >= 1) {
|
||||
//如果当前Byte的值大于等于1KB
|
||||
resultSize = DF.format(size / (float) KB) + "KB ";
|
||||
} else {
|
||||
resultSize = size + "B ";
|
||||
}
|
||||
return resultSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* inputStream 转 File
|
||||
* @param ins
|
||||
* @param name
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static File inputStreamToFile(InputStream ins, String name) throws Exception{
|
||||
File file = new File(System.getProperty("java.io.tmpdir") + name);
|
||||
if (file.exists()) {
|
||||
return file;
|
||||
}
|
||||
OutputStream os = new FileOutputStream(file);
|
||||
int bytesRead = 0;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
os.close();
|
||||
ins.close();
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件名解析成文件的上传路径
|
||||
*
|
||||
* @param file
|
||||
* @param filePath
|
||||
* @return 上传到服务器的文件名
|
||||
*/
|
||||
public static File upload(MultipartFile file, String filePath) {
|
||||
Date date = new Date();
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
|
||||
String name = getFileNameNoEx(file.getOriginalFilename());
|
||||
String suffix = getExtensionName(file.getOriginalFilename());
|
||||
String nowStr = "-" + format.format(date);
|
||||
try {
|
||||
String fileName = name + nowStr + "." + suffix;
|
||||
String path = filePath + fileName;
|
||||
File dest = new File(path);
|
||||
// 检测是否存在目录
|
||||
if (!dest.getParentFile().exists()) {
|
||||
dest.getParentFile().mkdirs();// 新建文件夹
|
||||
}
|
||||
String d = dest.getPath();
|
||||
file.transferTo(dest);// 文件写入
|
||||
return dest;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String fileToBase64(File file) throws Exception {
|
||||
FileInputStream inputFile = new FileInputStream(file);
|
||||
String base64 =null;
|
||||
byte[] buffer = new byte[(int)file.length()];
|
||||
inputFile.read(buffer);
|
||||
inputFile.close();
|
||||
base64=new Base64().encode(buffer);
|
||||
String encoded = base64.replaceAll("[\\s*\t\n\r]", "");
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel
|
||||
* @param list
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException {
|
||||
String tempPath =System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".xlsx";
|
||||
File file = new File(tempPath);
|
||||
BigExcelWriter writer= ExcelUtil.getBigWriter(file);
|
||||
// 一次性写出内容,使用默认样式,强制输出标题
|
||||
writer.write(list, true);
|
||||
//response为HttpServletResponse对象
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
|
||||
//test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
|
||||
response.setHeader("Content-Disposition","attachment;filename=file.xlsx");
|
||||
ServletOutputStream out=response.getOutputStream();
|
||||
// 终止后删除临时文件
|
||||
file.deleteOnExit();
|
||||
writer.flush(out, true);
|
||||
//此处记得关闭输出Servlet流
|
||||
IoUtil.close(out);
|
||||
}
|
||||
|
||||
public static String getFileType(String type) {
|
||||
String documents = "txt doc pdf ppt pps xlsx xls";
|
||||
String music = "mp3 wav wma mpa ram ra aac aif m4a";
|
||||
String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
|
||||
String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
|
||||
if(image.indexOf(type) != -1){
|
||||
return "图片";
|
||||
} else if(documents.indexOf(type) != -1){
|
||||
return "文档";
|
||||
} else if(music.indexOf(type) != -1){
|
||||
return "音乐";
|
||||
} else if(video.indexOf(type) != -1){
|
||||
return "视频";
|
||||
} else return "其他";
|
||||
}
|
||||
|
||||
public static String getFileTypeByMimeType(String type) {
|
||||
String mimeType = new MimetypesFileTypeMap().getContentType("." + type);
|
||||
return mimeType.split("\\/")[0];
|
||||
}
|
||||
public static void checkSize(long maxSize, long size) {
|
||||
if(size > (maxSize * 1024 * 1024)){
|
||||
throw new BadRequestException("文件超出规定大小");
|
||||
}
|
||||
}
|
||||
}
|
||||
157
yshop-common/src/main/java/co/yixiang/utils/OrderUtil.java
Normal file
157
yshop-common/src/main/java/co/yixiang/utils/OrderUtil.java
Normal file
@ -0,0 +1,157 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @ClassName OrderUtil
|
||||
* @Author hupeng <610796224@qq.com>
|
||||
* @Date 2019/9/13
|
||||
**/
|
||||
public class OrderUtil {
|
||||
|
||||
/**
|
||||
* 时间戳订单号
|
||||
* @return
|
||||
*/
|
||||
public static String orderSn(){
|
||||
Date date = DateUtil.date();
|
||||
return DateUtil.format(date,"yyyyMMddHHmmssSSS");
|
||||
}
|
||||
|
||||
/*
|
||||
* 将时间戳转换为时间
|
||||
*/
|
||||
public static String stampToDate(String s){
|
||||
String res;
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
long lt = new Long(s) * 1000;
|
||||
Date date = new Date(lt);
|
||||
res = simpleDateFormat.format(date);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取精确到秒的时间戳
|
||||
* @return
|
||||
**/
|
||||
public static int getSecondTimestampTwo(){
|
||||
String timestamp = String.valueOf(new Date().getTime()/1000);
|
||||
return Integer.valueOf(timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单状态名称
|
||||
* @param paid
|
||||
* @param status
|
||||
* @param shipping_type
|
||||
* @param refund_status
|
||||
* @return
|
||||
*/
|
||||
public static String orderStatusStr(int paid,int status,
|
||||
int shipping_type,int refund_status){
|
||||
String statusName = "";
|
||||
if(paid == 0 && status == 0){
|
||||
statusName = "未支付";
|
||||
}else if(paid == 1 && status == 0 && shipping_type == 1 && refund_status == 0){
|
||||
statusName = "未发货";
|
||||
}else if(paid == 1 && status == 0 && shipping_type == 2 && refund_status == 0){
|
||||
statusName = "未核销";
|
||||
}else if(paid == 1 && status == 1 && shipping_type ==1 && refund_status == 0){
|
||||
statusName = "待收货";
|
||||
}else if(paid == 1 && status == 1 && shipping_type == 2 && refund_status == 0){
|
||||
statusName = "未核销";
|
||||
}else if(paid == 1 && status == 2 && refund_status == 0){
|
||||
statusName = "待评价";
|
||||
}else if(paid == 1 && status == 3 && refund_status == 0){
|
||||
statusName = "已完成";
|
||||
}else if(paid == 1 && refund_status == 1){
|
||||
statusName = "退款中";
|
||||
}else if(paid == 1 && refund_status == 2){
|
||||
statusName = "已退款";
|
||||
}
|
||||
|
||||
return statusName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取状态数值
|
||||
* @param paid
|
||||
* @param status
|
||||
* @param refund_status
|
||||
* @return
|
||||
*/
|
||||
public static int orderStatus(int paid,int status,int refund_status){
|
||||
//todo 1-已付款 2-未发货 3-退款中 4-待收货 5-待评价 6-已完成 7-已退款
|
||||
int _status = 0;
|
||||
|
||||
if(paid == 0 && status == 0 && refund_status == 0){
|
||||
_status = 1;
|
||||
}else if(paid == 1 && status == 0 && refund_status == 0){
|
||||
_status = 2;
|
||||
}else if(paid == 1 && refund_status == 1){
|
||||
_status = 3;
|
||||
}else if(paid == 1 && status == 1 && refund_status == 0){
|
||||
_status = 4;
|
||||
}else if(paid == 1 && status == 2 && refund_status == 0){
|
||||
_status = 5;
|
||||
}else if(paid == 1 && status == 3 && refund_status == 0){
|
||||
_status = 6;
|
||||
}else if(paid == 1 && refund_status == 2){
|
||||
_status =7 ;
|
||||
}
|
||||
|
||||
return _status;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 支付方式
|
||||
* @param pay_type
|
||||
* @param paid
|
||||
* @return
|
||||
*/
|
||||
public static String payTypeName(String pay_type, int paid){
|
||||
String payTypeName = "";
|
||||
if(paid == 1 ){
|
||||
switch(pay_type){
|
||||
case "weixin":
|
||||
payTypeName = "微信支付";
|
||||
break;
|
||||
case "yue":
|
||||
payTypeName = "余额支付";
|
||||
break;
|
||||
case "offline":
|
||||
payTypeName = "线下支付";
|
||||
break;
|
||||
default:
|
||||
payTypeName = "其他支付";
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
switch(pay_type){
|
||||
default:
|
||||
payTypeName = "未支付";
|
||||
break;
|
||||
case "offline":
|
||||
payTypeName = "线下支付";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return payTypeName;
|
||||
}
|
||||
|
||||
//todo 订单类型
|
||||
public static String orderType(int pink_id){
|
||||
return "普通订单";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
58
yshop-common/src/main/java/co/yixiang/utils/PageUtil.java
Normal file
58
yshop-common/src/main/java/co/yixiang/utils/PageUtil.java
Normal file
@ -0,0 +1,58 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 分页工具
|
||||
* @author Zheng Jie
|
||||
* @date 2018-12-10
|
||||
*/
|
||||
public class PageUtil extends cn.hutool.core.util.PageUtil {
|
||||
|
||||
/**
|
||||
* List 分页
|
||||
* @param page
|
||||
* @param size
|
||||
* @param list
|
||||
* @return
|
||||
*/
|
||||
public static List toPage(int page, int size , List list) {
|
||||
int fromIndex = page * size;
|
||||
int toIndex = page * size + size;
|
||||
|
||||
if(fromIndex > list.size()){
|
||||
return new ArrayList();
|
||||
} else if(toIndex >= list.size()) {
|
||||
return list.subList(fromIndex,list.size());
|
||||
} else {
|
||||
return list.subList(fromIndex,toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Page 数据处理,预防redis反序列化报错
|
||||
* @param page
|
||||
* @return
|
||||
*/
|
||||
public static Map toPage(Page page) {
|
||||
Map<String,Object> map = new LinkedHashMap<>(2);
|
||||
map.put("content",page.getContent());
|
||||
map.put("totalElements",page.getTotalElements());
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object
|
||||
* @param totalElements
|
||||
* @return
|
||||
*/
|
||||
public static Map toPage(Object object, Object totalElements) {
|
||||
Map<String,Object> map = new LinkedHashMap<>(2);
|
||||
map.put("content",object);
|
||||
map.put("totalElements",totalElements);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
155
yshop-common/src/main/java/co/yixiang/utils/QueryHelp.java
Normal file
155
yshop-common/src/main/java/co/yixiang/utils/QueryHelp.java
Normal file
@ -0,0 +1,155 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import co.yixiang.annotation.Query;
|
||||
import javax.persistence.criteria.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2019-6-4 14:59:48
|
||||
*/
|
||||
@Slf4j
|
||||
public class QueryHelp {
|
||||
|
||||
/**
|
||||
* @描述 : 转换为Predicate
|
||||
* @作者 : Dong ZhaoYang
|
||||
* @日期 : 2017/8/7
|
||||
* @时间 : 17:25
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) {
|
||||
List<Predicate> list = new ArrayList<>();
|
||||
|
||||
if(query == null){
|
||||
return cb.and(list.toArray(new Predicate[list.size()]));
|
||||
}
|
||||
try {
|
||||
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
|
||||
for (Field field : fields) {
|
||||
boolean accessible = field.isAccessible();
|
||||
field.setAccessible(true);
|
||||
Query q = field.getAnnotation(Query.class);
|
||||
if (q != null) {
|
||||
String propName = q.propName();
|
||||
String joinName = q.joinName();
|
||||
String blurry = q.blurry();
|
||||
String attributeName = isBlank(propName) ? field.getName() : propName;
|
||||
Class<?> fieldType = field.getType();
|
||||
Object val = field.get(query);
|
||||
if (ObjectUtil.isNull(val) || "".equals(val)) {
|
||||
continue;
|
||||
}
|
||||
Join join = null;
|
||||
// 模糊多字段
|
||||
if (ObjectUtil.isNotEmpty(blurry)) {
|
||||
String[] blurrys = blurry.split(",");
|
||||
List<Predicate> orPredicate = new ArrayList<>();
|
||||
for (String s : blurrys) {
|
||||
orPredicate.add(cb.like(root.get(s)
|
||||
.as(String.class), "%" + val.toString() + "%"));
|
||||
}
|
||||
Predicate[] p = new Predicate[orPredicate.size()];
|
||||
list.add(cb.or(orPredicate.toArray(p)));
|
||||
continue;
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(joinName)) {
|
||||
String[] joinNames = joinName.split(">");
|
||||
for (String name : joinNames) {
|
||||
switch (q.join()) {
|
||||
case LEFT:
|
||||
if(ObjectUtil.isNotEmpty(join)){
|
||||
join = join.join(name, JoinType.LEFT);
|
||||
} else {
|
||||
join = root.join(name, JoinType.LEFT);
|
||||
}
|
||||
break;
|
||||
case RIGHT:
|
||||
if(ObjectUtil.isNotEmpty(join)){
|
||||
join = join.join(name, JoinType.RIGHT);
|
||||
} else {
|
||||
join = root.join(name, JoinType.RIGHT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (q.type()) {
|
||||
case EQUAL:
|
||||
list.add(cb.equal(getExpression(attributeName,join,root)
|
||||
.as((Class<? extends Comparable>) fieldType),val));
|
||||
break;
|
||||
case GREATER_THAN:
|
||||
list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root)
|
||||
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
|
||||
break;
|
||||
case LESS_THAN:
|
||||
list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root)
|
||||
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
|
||||
break;
|
||||
case LESS_THAN_NQ:
|
||||
list.add(cb.lessThan(getExpression(attributeName,join,root)
|
||||
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
|
||||
break;
|
||||
case INNER_LIKE:
|
||||
list.add(cb.like(getExpression(attributeName,join,root)
|
||||
.as(String.class), "%" + val.toString() + "%"));
|
||||
break;
|
||||
case LEFT_LIKE:
|
||||
list.add(cb.like(getExpression(attributeName,join,root)
|
||||
.as(String.class), "%" + val.toString()));
|
||||
break;
|
||||
case RIGHT_LIKE:
|
||||
list.add(cb.like(getExpression(attributeName,join,root)
|
||||
.as(String.class), val.toString() + "%"));
|
||||
case IN:
|
||||
if (CollUtil.isNotEmpty((Collection<Long>)val)) {
|
||||
list.add(getExpression(attributeName,join,root).in((Collection<Long>) val));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
field.setAccessible(accessible);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return cb.and(list.toArray(new Predicate[list.size()]));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T, R> Expression<T> getExpression(String attributeName, Join join, Root<R> root) {
|
||||
if (ObjectUtil.isNotEmpty(join)) {
|
||||
return join.get(attributeName);
|
||||
} else {
|
||||
return root.get(attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean isBlank(final CharSequence cs) {
|
||||
int strLen;
|
||||
if (cs == null || (strLen = cs.length()) == 0) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
if (Character.isWhitespace(cs.charAt(i)) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<Field> getAllFields(Class clazz, List<Field> fields) {
|
||||
if (clazz != null) {
|
||||
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
|
||||
getAllFields(clazz.getSuperclass(), fields);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 获取 HttpServletRequest
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
*/
|
||||
public class RequestHolder {
|
||||
|
||||
public static HttpServletRequest getHttpServletRequest() {
|
||||
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import co.yixiang.exception.BadRequestException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* 获取当前登录的用户
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-17
|
||||
*/
|
||||
public class SecurityUtils {
|
||||
|
||||
public static UserDetails getUserDetails() {
|
||||
UserDetails userDetails = null;
|
||||
try {
|
||||
userDetails = (UserDetails) org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
} catch (Exception e) {
|
||||
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "登录状态过期");
|
||||
}
|
||||
return userDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统用户名称
|
||||
* @return 系统用户名称
|
||||
*/
|
||||
public static String getUsername(){
|
||||
Object obj = getUserDetails();
|
||||
JSONObject json = new JSONObject(obj);
|
||||
return json.get("username", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统用户id
|
||||
* @return 系统用户id
|
||||
*/
|
||||
public static Long getUserId(){
|
||||
Object obj = getUserDetails();
|
||||
JSONObject json = new JSONObject(obj);
|
||||
return json.get("id", Long.class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* @author
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
|
||||
|
||||
private static ApplicationContext applicationContext = null;
|
||||
|
||||
/**
|
||||
* 取得存储在静态变量中的ApplicationContext.
|
||||
*/
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
assertContextInjected();
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getBean(String name) {
|
||||
assertContextInjected();
|
||||
return (T) applicationContext.getBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getBean(Class<T> requiredType) {
|
||||
assertContextInjected();
|
||||
return applicationContext.getBean(requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查ApplicationContext不为空.
|
||||
*/
|
||||
private static void assertContextInjected() {
|
||||
if (applicationContext == null) {
|
||||
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
|
||||
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除SpringContextHolder中的ApplicationContext为Null.
|
||||
*/
|
||||
public static void clearHolder() {
|
||||
log.debug("清除SpringContextHolder中的ApplicationContext:"
|
||||
+ applicationContext);
|
||||
applicationContext = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
SpringContextHolder.clearHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
if (SpringContextHolder.applicationContext != null) {
|
||||
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
|
||||
}
|
||||
SpringContextHolder.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
200
yshop-common/src/main/java/co/yixiang/utils/StringUtils.java
Normal file
200
yshop-common/src/main/java/co/yixiang/utils/StringUtils.java
Normal file
@ -0,0 +1,200 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import org.lionsoul.ip2region.DataBlock;
|
||||
import org.lionsoul.ip2region.DbConfig;
|
||||
import org.lionsoul.ip2region.DbSearcher;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
|
||||
*/
|
||||
public class StringUtils extends org.apache.commons.lang3.StringUtils {
|
||||
|
||||
private static final char SEPARATOR = '_';
|
||||
private static final String CHARSET_NAME = "UTF-8";
|
||||
|
||||
/**
|
||||
* 是否包含字符串
|
||||
*
|
||||
* @param str 验证字符串
|
||||
* @param strs 字符串组
|
||||
* @return 包含返回true
|
||||
*/
|
||||
public static boolean inString(String str, String... strs) {
|
||||
if (str != null) {
|
||||
for (String s : strs) {
|
||||
if (str.equals(trim(s))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰命名法工具
|
||||
*
|
||||
* @return toCamelCase(" hello_world ") == "helloWorld"
|
||||
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
|
||||
* toUnderScoreCase("helloWorld") = "hello_world"
|
||||
*/
|
||||
public static String toCamelCase(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
s = s.toLowerCase();
|
||||
|
||||
StringBuilder sb = new StringBuilder(s.length());
|
||||
boolean upperCase = false;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
if (c == SEPARATOR) {
|
||||
upperCase = true;
|
||||
} else if (upperCase) {
|
||||
sb.append(Character.toUpperCase(c));
|
||||
upperCase = false;
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰命名法工具
|
||||
*
|
||||
* @return toCamelCase(" hello_world ") == "helloWorld"
|
||||
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
|
||||
* toUnderScoreCase("helloWorld") = "hello_world"
|
||||
*/
|
||||
public static String toCapitalizeCamelCase(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
s = toCamelCase(s);
|
||||
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰命名法工具
|
||||
*
|
||||
* @return toCamelCase(" hello_world ") == "helloWorld"
|
||||
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
|
||||
* toUnderScoreCase("helloWorld") = "hello_world"
|
||||
*/
|
||||
public static String toUnderScoreCase(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean upperCase = false;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
boolean nextUpperCase = true;
|
||||
|
||||
if (i < (s.length() - 1)) {
|
||||
nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
|
||||
}
|
||||
|
||||
if ((i > 0) && Character.isUpperCase(c)) {
|
||||
if (!upperCase || !nextUpperCase) {
|
||||
sb.append(SEPARATOR);
|
||||
}
|
||||
upperCase = true;
|
||||
} else {
|
||||
upperCase = false;
|
||||
}
|
||||
|
||||
sb.append(Character.toLowerCase(c));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ip地址
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public static String getIP(HttpServletRequest request) {
|
||||
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();
|
||||
}
|
||||
String[] ips = ip.split(",");
|
||||
return "0:0:0:0:0:0:0:1".equals(ips[0])?"127.0.0.1":ips[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ip获取详细地址
|
||||
* @param ip
|
||||
* @return
|
||||
*/
|
||||
public static String getCityInfo(String ip) {
|
||||
try {
|
||||
String path = "ip2region/ip2region.db";
|
||||
String name = "ip2region.db";
|
||||
int algorithm = DbSearcher.BTREE_ALGORITHM;
|
||||
DbConfig config = new DbConfig();
|
||||
File file = FileUtil.inputStreamToFile(new ClassPathResource(path).getStream(), name);
|
||||
DbSearcher searcher = new DbSearcher(config, file.getPath());
|
||||
Method method = null;
|
||||
switch (algorithm) {
|
||||
case DbSearcher.BTREE_ALGORITHM:
|
||||
method = searcher.getClass().getMethod("btreeSearch", String.class);
|
||||
break;
|
||||
case DbSearcher.BINARY_ALGORITHM:
|
||||
method = searcher.getClass().getMethod("binarySearch", String.class);
|
||||
break;
|
||||
case DbSearcher.MEMORY_ALGORITYM:
|
||||
method = searcher.getClass().getMethod("memorySearch", String.class);
|
||||
break;
|
||||
default:
|
||||
method = searcher.getClass().getMethod("memorySearch", String.class);
|
||||
break;
|
||||
}
|
||||
DataBlock dataBlock = null;
|
||||
dataBlock = (DataBlock) method.invoke(searcher, ip);
|
||||
String address = dataBlock.getRegion().replace("0|","");
|
||||
if(address.charAt(address.length()-1) == '|'){
|
||||
address = address.substring(0,address.length() - 1);
|
||||
}
|
||||
return address.equals(ElAdminConstant.REGION)?"内网IP":address;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当天是周几
|
||||
*/
|
||||
public static String getWeekDay(){
|
||||
String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(new Date());
|
||||
|
||||
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
|
||||
if (w < 0){
|
||||
w = 0;
|
||||
}
|
||||
return weekDays[w];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import co.yixiang.exception.BadRequestException;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* 异常工具
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-06
|
||||
*/
|
||||
public class ThrowableUtil {
|
||||
|
||||
/**
|
||||
* 获取堆栈信息
|
||||
* @param throwable
|
||||
* @return
|
||||
*/
|
||||
public static String getStackTrace(Throwable throwable){
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
try {
|
||||
throwable.printStackTrace(pw);
|
||||
return sw.toString();
|
||||
} finally {
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void throwForeignKeyException(Throwable e, String msg){
|
||||
Throwable t = e.getCause();
|
||||
while ((t != null) && !(t instanceof ConstraintViolationException)) {
|
||||
t = t.getCause();
|
||||
}
|
||||
if (t instanceof ConstraintViolationException) {
|
||||
throw new BadRequestException(msg);
|
||||
}
|
||||
throw new BadRequestException("删除失败:" + t.getMessage());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import lombok.var;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
public class TranslatorUtil {
|
||||
|
||||
public static String translate(String word){
|
||||
try {
|
||||
String url = "https://translate.googleapis.com/translate_a/single?" +
|
||||
"client=gtx&" +
|
||||
"sl=en" +
|
||||
"&tl=zh-CN" +
|
||||
"&dt=t&q=" + URLEncoder.encode(word, "UTF-8");
|
||||
|
||||
URL obj = new URL(url);
|
||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
||||
con.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||
|
||||
BufferedReader in = new BufferedReader(
|
||||
new InputStreamReader(con.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuffer response = new StringBuffer();
|
||||
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
return parseResult(response.toString());
|
||||
}catch (Exception e){
|
||||
return word;
|
||||
}
|
||||
}
|
||||
|
||||
private static String parseResult(String inputJson) throws Exception {
|
||||
JSONArray jsonArray = new JSONArray(inputJson);
|
||||
JSONArray jsonArray2 = (JSONArray) jsonArray.get(0);
|
||||
String result ="";
|
||||
|
||||
for(var i = 0; i < jsonArray2.size(); i ++){
|
||||
result += ((JSONArray) jsonArray2.get(i)).get(0).toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
89
yshop-common/src/main/java/co/yixiang/utils/TreeUtil.java
Normal file
89
yshop-common/src/main/java/co/yixiang/utils/TreeUtil.java
Normal file
@ -0,0 +1,89 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName TreeUtil
|
||||
* @Author hupeng <610796224@qq.com>
|
||||
* @Date 2019/10/22
|
||||
**/
|
||||
public class TreeUtil {
|
||||
/**
|
||||
* 获得指定节点下所有归档
|
||||
* @param list
|
||||
* @param parentId
|
||||
* @return
|
||||
*/
|
||||
public static List<CateDTO> list2TreeConverter(List<CateDTO> list, int parentId) {
|
||||
List<CateDTO> returnList = new ArrayList<>();
|
||||
|
||||
for (CateDTO res : list) {
|
||||
//判断对象是否为根节点
|
||||
|
||||
if (res.getPid() == parentId) {
|
||||
//该节点为根节点,开始递归
|
||||
|
||||
recursionFn(list, res); //通过递归为节点设置childList
|
||||
|
||||
returnList.add(res);
|
||||
}
|
||||
}
|
||||
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归列表
|
||||
* 通过递归,给指定t节点设置childList
|
||||
* @param list
|
||||
* @param t
|
||||
*/
|
||||
public static void recursionFn(List<CateDTO> list, CateDTO t) {
|
||||
//只能获取当前t节点的子节点集,并不是所有子节点集
|
||||
List<CateDTO> childsList = getChildList(list, t);
|
||||
//设置他的子集对象集
|
||||
t.setChildren(childsList);
|
||||
|
||||
//迭代子集对象集
|
||||
for (CateDTO nextChild : childsList) { //遍历完,则退出递归
|
||||
|
||||
//判断子集对象是否还有子节点
|
||||
if (!CollectionUtils.isEmpty(childsList)) {
|
||||
//有下一个子节点,继续递归
|
||||
recursionFn(list, nextChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定节点下的所有子节点
|
||||
* @param list
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
public static List<CateDTO> getChildList(List<CateDTO> list, CateDTO t) {
|
||||
List<CateDTO> childsList = new ArrayList<CateDTO>();
|
||||
//遍历集合元素,如果元素的Parentid==指定元素的id,则说明是该元素的子节点
|
||||
for (CateDTO t1 : list) {
|
||||
if (t1.getPid() == t.getId() ) {
|
||||
childsList.add(t1);
|
||||
}
|
||||
}
|
||||
|
||||
return childsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否还有下一个子节点
|
||||
* @param list
|
||||
* @param t
|
||||
*/
|
||||
public static boolean hasChild(List<CateDTO> list, CateDTO t) {
|
||||
return getChildList(list, t).size() > 0 ? true : false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import co.yixiang.exception.BadRequestException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 验证工具
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
*/
|
||||
public class ValidationUtil{
|
||||
|
||||
/**
|
||||
* 验证空
|
||||
* @param optional
|
||||
*/
|
||||
public static void isNull(Optional optional, String entity,String parameter , Object value){
|
||||
if(!optional.isPresent()){
|
||||
String msg = entity
|
||||
+ " 不存在 "
|
||||
+"{ "+ parameter +":"+ value.toString() +" }";
|
||||
throw new BadRequestException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否为邮箱
|
||||
* @param string
|
||||
* @return
|
||||
*/
|
||||
public static boolean isEmail(String string) {
|
||||
if (string == null){
|
||||
return false;
|
||||
}
|
||||
String regEx1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
|
||||
return string.matches(regEx1);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EncryptUtilsTest {
|
||||
|
||||
/**
|
||||
* 对称加密
|
||||
*/
|
||||
@Test
|
||||
public void testDesEncrypt() {
|
||||
try {
|
||||
Assert.assertEquals("7772841DC6099402", EncryptUtils.desEncrypt("123456"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对称解密
|
||||
*/
|
||||
@Test
|
||||
public void testDesDecrypt() {
|
||||
try {
|
||||
Assert.assertEquals("123456", EncryptUtils.desDecrypt("7772841DC6099402"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class FileUtilTest {
|
||||
|
||||
@Test
|
||||
public void testToFile() {
|
||||
long retval = FileUtil.toFile(new MockMultipartFile("foo", (byte[]) null)).getTotalSpace();
|
||||
assertEquals(500695072768L, retval);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExtensionName() {
|
||||
Assert.assertEquals("foo", FileUtil.getExtensionName("foo"));
|
||||
Assert.assertEquals("exe", FileUtil.getExtensionName("bar.exe"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFileNameNoEx() {
|
||||
Assert.assertEquals("foo", FileUtil.getFileNameNoEx("foo"));
|
||||
Assert.assertEquals("bar", FileUtil.getFileNameNoEx("bar.txt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSize() {
|
||||
Assert.assertEquals("1000B ", FileUtil.getSize(1000));
|
||||
Assert.assertEquals("1.00KB ", FileUtil.getSize(1024));
|
||||
Assert.assertEquals("1.00MB ", FileUtil.getSize(1048576));
|
||||
Assert.assertEquals("1.00GB ", FileUtil.getSize(1073741824));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class StringUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testInString() {
|
||||
assertTrue(StringUtils.inString("?", "?"));
|
||||
assertFalse(StringUtils.inString("?", new String[]{}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToCamelCase() {
|
||||
assertNull(StringUtils.toCamelCase(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToCapitalizeCamelCase() {
|
||||
assertNull(StringUtils.toCapitalizeCamelCase(null));
|
||||
Assert.assertEquals("HelloWorld", StringUtils.toCapitalizeCamelCase("hello_world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToUnderScoreCase() {
|
||||
assertNull(StringUtils.toUnderScoreCase(null));
|
||||
Assert.assertEquals("hello_world", StringUtils.toUnderScoreCase("helloWorld"));
|
||||
Assert.assertEquals("\u0000\u0000", StringUtils.toUnderScoreCase("\u0000\u0000"));
|
||||
Assert.assertEquals("\u0000_a", StringUtils.toUnderScoreCase("\u0000A"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetWeekDay() {
|
||||
SimpleDateFormat simpleDateformat = new SimpleDateFormat("E");
|
||||
Assert.assertEquals(simpleDateformat.format(new Date()), StringUtils.getWeekDay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIP() {
|
||||
Assert.assertEquals("127.0.0.1", StringUtils.getIP(new MockHttpServletRequest()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user