init
This commit is contained in:
parent
3460a0f5df
commit
e6904a058a
|
@ -0,0 +1,48 @@
|
|||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.sinosoft</groupId>
|
||||
<artifactId>cloud-plus</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>cloud-plus-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>cloud-plus-common</name>
|
||||
<description>cloud-plus-公共组件</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-bean-validators</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.nutz</groupId>
|
||||
<artifactId>nutz</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,168 @@
|
|||
package com.sinosoft.cloud.plus.dto;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.json.JsonFormat;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Builder.Default;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
* @param <T>
|
||||
* 数据泛型
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Result<T> {
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
*/
|
||||
public enum OperationState {
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
SUCCESS,
|
||||
/**
|
||||
* 失败
|
||||
*/
|
||||
FAIL,
|
||||
/**
|
||||
* 异常
|
||||
*/
|
||||
EXCEPTION;
|
||||
|
||||
}
|
||||
|
||||
@Default
|
||||
@ApiModelProperty(value = "响应扩展数据", required = false)
|
||||
private NutMap ext = new NutMap();
|
||||
|
||||
@Default
|
||||
@ApiModelProperty(value = "响应状态", required = true)
|
||||
private OperationState state = OperationState.SUCCESS;
|
||||
|
||||
@ApiModelProperty(value = "错误信息列表")
|
||||
private String[] errors;
|
||||
|
||||
@ApiModelProperty(value = "响应数据", required = true)
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 返回成功
|
||||
*
|
||||
* @return 成功的结果
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static Result success() {
|
||||
return Result.builder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 携带数据返回成功
|
||||
*
|
||||
* @param <T>
|
||||
* 数据泛型
|
||||
* @param t
|
||||
* 数据
|
||||
* @return 成功的结果
|
||||
*/
|
||||
public static <T> Result<T> success(T t) {
|
||||
return Result.<T> builder().data(t).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回失败及原因
|
||||
*
|
||||
* @param errors
|
||||
* 失败原因
|
||||
* @return 失败的结果
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static Result fail(String... errors) {
|
||||
return Result.builder().state(OperationState.FAIL).errors(errors).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回异常及原因
|
||||
*
|
||||
* @param errors
|
||||
* 异常原因
|
||||
* @return 异常的结果
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static Result exception(String... errors) {
|
||||
return Result.builder().state(OperationState.EXCEPTION).errors(errors).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回异常及原因
|
||||
*
|
||||
* @param errors
|
||||
* 异常原因
|
||||
* @return 异常的结果
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static Result exception(List<String> errors) {
|
||||
return Result.builder().state(OperationState.EXCEPTION).errors(errors.toArray(new String[errors.size()])).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回异常及原因
|
||||
*
|
||||
* @param exceptions
|
||||
* 异常
|
||||
* @return 异常的结果
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static Result exception(Throwable... exceptions) {
|
||||
return exception(Arrays.stream(exceptions).map(Throwable::getMessage).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加扩展数据
|
||||
*
|
||||
* @param key
|
||||
* 数据key
|
||||
* @param value
|
||||
* 数据
|
||||
* @return 返回结果对象
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Result addExtData(String key, Object value) {
|
||||
getExt().setv(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*
|
||||
* @return 是否成功标识
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return getState() == OperationState.SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Json.toJson(this, JsonFormat.forLook());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
package com.sinosoft.cloud.plus.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.repo.Base64;
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
*/
|
||||
public class AES {
|
||||
|
||||
private AES() {}
|
||||
|
||||
public static final String AES_NAME = "AES";
|
||||
public static final String CHER_SET = "UTF-8";
|
||||
|
||||
public static final String DEFAULT_KEY = "EBD0B5D2-F4E7-453A-9E16-01AE8F6E2977";
|
||||
|
||||
private static Log log = Logs.get();
|
||||
|
||||
/**
|
||||
* 使用默认密钥加密
|
||||
*
|
||||
* @param sSrc
|
||||
* 明文
|
||||
* @return 密文
|
||||
*/
|
||||
public static String encrypt(String sSrc) {
|
||||
return encrypt(sSrc, DEFAULT_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param sSrc
|
||||
* 明文
|
||||
* @param sKey
|
||||
* 密钥
|
||||
* @return 密文
|
||||
*/
|
||||
public static String encrypt(String sSrc, String sKey) {
|
||||
try {
|
||||
if (sKey == null) {
|
||||
log.error("key 不能为空!");
|
||||
return null;
|
||||
}
|
||||
// 判断Key是否为16位
|
||||
if (sKey.length() != 16) {
|
||||
log.error("key 长度不是16位");
|
||||
return null;
|
||||
}
|
||||
byte[] raw = sKey.getBytes(CHER_SET);
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(raw, AES_NAME);
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");// "算法/模式/补码方式"
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
|
||||
byte[] encrypted = cipher.doFinal(sSrc.getBytes(CHER_SET));
|
||||
return Base64.encodeToString(encrypted, false);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密(使用默认密钥)
|
||||
*
|
||||
* @param sSrc
|
||||
* 密文
|
||||
* @return 明文
|
||||
*/
|
||||
public static String decrypt(String sSrc) {
|
||||
return decrypt(sSrc, DEFAULT_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param sSrc
|
||||
* 密文
|
||||
* @param sKey
|
||||
* 密钥
|
||||
* @return 明文
|
||||
*/
|
||||
public static String decrypt(String sSrc, String sKey) {
|
||||
try {
|
||||
if (sKey == null) {
|
||||
log.error("key 不能为空!");
|
||||
return null;
|
||||
}
|
||||
if (sKey.length() != 16) {
|
||||
log.error("key 长度不是16位");
|
||||
return null;
|
||||
}
|
||||
byte[] raw = sKey.getBytes(CHER_SET);
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(raw, AES_NAME);
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
|
||||
byte[] encrypted1 = Base64.decode(sSrc);// 先用base64解密
|
||||
byte[] original = cipher.doFinal(encrypted1);
|
||||
return new String(original, CHER_SET);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
package com.sinosoft.cloud.plus.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
*/
|
||||
public class Ariths {
|
||||
private static final int DEF_DIV_SCALE = 10;
|
||||
|
||||
/**
|
||||
* 提供精确的加法运算。
|
||||
*
|
||||
* @param v1
|
||||
* 被加数
|
||||
* @param v2
|
||||
* 加数
|
||||
* @return 两个参数的和
|
||||
*/
|
||||
|
||||
public static double add(double v1, double v2) {
|
||||
BigDecimal b1 = BigDecimal.valueOf(v1);
|
||||
BigDecimal b2 = BigDecimal.valueOf(v2);
|
||||
return b1.add(b2).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
|
||||
*
|
||||
* @param v1
|
||||
* 被除数
|
||||
* @param v2
|
||||
* 除数
|
||||
* @return 两个参数的商
|
||||
*/
|
||||
|
||||
public static double div(double v1, double v2) {
|
||||
return div(v1, v2, DEF_DIV_SCALE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
|
||||
*
|
||||
* @param v1
|
||||
* 被除数
|
||||
* @param v2
|
||||
* 除数
|
||||
* @param scale
|
||||
* 表示表示需要精确到小数点以后几位。
|
||||
* @return 两个参数的商
|
||||
*/
|
||||
|
||||
public static double div(double v1, double v2, int scale) {
|
||||
if (scale < 0) {
|
||||
throw new ScaleMustBePositiveIntegerOrZeroException();
|
||||
}
|
||||
BigDecimal b1 = new BigDecimal(Double.toString(v1));
|
||||
BigDecimal b2 = new BigDecimal(Double.toString(v2));
|
||||
return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
|
||||
}
|
||||
|
||||
public static class ScaleMustBePositiveIntegerOrZeroException extends IllegalArgumentException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public ScaleMustBePositiveIntegerOrZeroException() {
|
||||
super("The scale must be a positive integer or zero");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供精确的乘法运算。
|
||||
*
|
||||
* @param v1
|
||||
* 被乘数
|
||||
* @param v2
|
||||
* 乘数
|
||||
* @return 两个参数的积
|
||||
*/
|
||||
|
||||
public static double mul(double v1, double v2) {
|
||||
BigDecimal b1 = BigDecimal.valueOf(v1);
|
||||
BigDecimal b2 = BigDecimal.valueOf(v2);
|
||||
return b1.multiply(b2).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供精确的乘法运算。
|
||||
*
|
||||
* @param v1
|
||||
* 被乘数
|
||||
* @param v2
|
||||
* 乘数
|
||||
* @return 两个参数的积的int表示
|
||||
*/
|
||||
public static int mulToInt(double v1, double v2) {
|
||||
BigDecimal b1 = BigDecimal.valueOf(v1);
|
||||
BigDecimal b2 = BigDecimal.valueOf(v2);
|
||||
return b1.multiply(b2).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供精确的小数位四舍五入处理。
|
||||
*
|
||||
* @param v
|
||||
* 需要四舍五入的数字
|
||||
* @param scale
|
||||
* 小数点后保留几位
|
||||
* @return 四舍五入后的结果
|
||||
*/
|
||||
|
||||
public static double round(double v, int scale) {
|
||||
if (scale < 0) {
|
||||
throw new ScaleMustBePositiveIntegerOrZeroException();
|
||||
}
|
||||
BigDecimal b = new BigDecimal(Double.toString(v));
|
||||
BigDecimal one = new BigDecimal("1");
|
||||
return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供精确的小数位四舍五入处理。
|
||||
*
|
||||
* @param v
|
||||
* 需要四舍五入的数字
|
||||
* @param scale
|
||||
* 小数点后保留几位
|
||||
* @param mode
|
||||
* 进位模式
|
||||
* @return 结果
|
||||
*/
|
||||
public static double round(double v, int scale, RoundingMode mode) {
|
||||
if (scale < 0) {
|
||||
throw new ScaleMustBePositiveIntegerOrZeroException();
|
||||
}
|
||||
BigDecimal b = BigDecimal.valueOf(v);
|
||||
BigDecimal one = BigDecimal.valueOf(1);
|
||||
return b.divide(one, scale, mode).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供精确的减法运算。
|
||||
*
|
||||
* @param v1
|
||||
* 被减数
|
||||
* @param v2
|
||||
* 减数
|
||||
* @return 两个参数的差
|
||||
*/
|
||||
|
||||
public static double sub(double v1, double v2) {
|
||||
BigDecimal b1 = BigDecimal.valueOf(v1);
|
||||
BigDecimal b2 = BigDecimal.valueOf(v2);
|
||||
return b1.subtract(b2).doubleValue();
|
||||
}
|
||||
|
||||
private Ariths() {}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package com.sinosoft.cloud.plus.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
*/
|
||||
public class Builder<T> {
|
||||
private final Supplier<T> instantiator;
|
||||
private List<Consumer<T>> modifiers = new ArrayList<>();
|
||||
|
||||
public Builder(Supplier<T> instantiator) {
|
||||
this.instantiator = instantiator;
|
||||
}
|
||||
|
||||
public static <T> Builder<T> of(Supplier<T> instantiator) {
|
||||
return new Builder<>(instantiator);
|
||||
}
|
||||
|
||||
public <P1> Builder<T> with(Consumer1<T, P1> consumer, P1 p1) {
|
||||
Consumer<T> c = instance -> consumer.accept(instance, p1);
|
||||
modifiers.add(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <P1, P2> Builder<T> with(Consumer2<T, P1, P2> consumer, P1 p1, P2 p2) {
|
||||
Consumer<T> c = instance -> consumer.accept(instance, p1, p2);
|
||||
modifiers.add(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <P1, P2, P3> Builder<T> with(Consumer3<T, P1, P2, P3> consumer, P1 p1, P2 p2, P3 p3) {
|
||||
Consumer<T> c = instance -> consumer.accept(instance, p1, p2, p3);
|
||||
modifiers.add(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
public T build() {
|
||||
T value = instantiator.get();
|
||||
modifiers.forEach(modifier -> modifier.accept(value));
|
||||
modifiers.clear();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1 参数 Consumer
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Consumer1<T, P1> {
|
||||
void accept(T t, P1 p1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 2 参数 Consumer
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Consumer2<T, P1, P2> {
|
||||
void accept(T t, P1 p1, P2 p2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 3 参数 Consumer
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Consumer3<T, P1, P2, P3> {
|
||||
void accept(T t, P1 p1, P2 p2, P3 p3);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package com.sinosoft.cloud.plus.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.nutz.lang.Lang;
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
*/
|
||||
public class CharSequence {
|
||||
/**
|
||||
* 解码
|
||||
*
|
||||
* @param data
|
||||
* 数据数组
|
||||
* @return 原数据
|
||||
*/
|
||||
public static String decode(Integer[] data) {
|
||||
return decode(Lang.array2list(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码
|
||||
*
|
||||
* @param data
|
||||
* 数据list
|
||||
* @return 原数据
|
||||
*/
|
||||
public static String decode(List<Integer> data) {
|
||||
return new CharSequence(data).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码
|
||||
*
|
||||
* @param data
|
||||
* 数据串 用 ',' 分隔
|
||||
* @return 原数据
|
||||
*/
|
||||
public static String decode(String data) {
|
||||
List<Integer> value = parse(data);
|
||||
return decode(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* NB解码
|
||||
*
|
||||
* @param data
|
||||
* 数据
|
||||
* @param times
|
||||
* 次数
|
||||
* @return 解码结果
|
||||
*/
|
||||
public static String decode(String data, int times) {
|
||||
String target = data;
|
||||
String cache = null;
|
||||
for (int i = 0; i < times; i++) {
|
||||
try {
|
||||
target = decode(target);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return cache;
|
||||
}
|
||||
cache = target;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码
|
||||
*
|
||||
* @param info
|
||||
* 带编码字符串
|
||||
* @return 编码结果串
|
||||
*/
|
||||
public static List<Integer> encode(String info) {
|
||||
return new CharSequence(info).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码成串
|
||||
*
|
||||
* @param info
|
||||
* 数据
|
||||
* @return 返回串
|
||||
*/
|
||||
public static String encodeToString(String info) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Integer i : encode(info)) {
|
||||
builder.append(i + ",");
|
||||
}
|
||||
if (builder.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
return builder.substring(0, builder.length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码成串
|
||||
*
|
||||
* @param info
|
||||
* 数据
|
||||
* @param times
|
||||
* 次数
|
||||
* @return 返回串
|
||||
*/
|
||||
public static String encodeToString(String info, int times) {
|
||||
String target = info;
|
||||
for (int i = 0; i < times; i++) {
|
||||
target = encodeToString(target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private static List<Integer> parse(String data) {
|
||||
List<Integer> target = new ArrayList<>();
|
||||
String[] infos = data.split(",");
|
||||
for (String info : infos) {
|
||||
target.add(Integer.parseInt(info.trim()));
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private List<Integer> value = new ArrayList<>();
|
||||
|
||||
private String stringValue;
|
||||
|
||||
public CharSequence(List<Integer> value) {
|
||||
this.value = value;
|
||||
this.stringValue = toString();
|
||||
}
|
||||
|
||||
private CharSequence(String in) {
|
||||
for (char c : in.toCharArray()) {
|
||||
value.add((int) c);
|
||||
}
|
||||
this.stringValue = in;
|
||||
}
|
||||
|
||||
public String getStringValue() {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
public List<Integer> getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package com.sinosoft.cloud.plus.utils;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.repo.Base64;
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
*/
|
||||
public class DES {
|
||||
private DES() {
|
||||
}
|
||||
|
||||
private static final String DES_NAME = "DES";
|
||||
|
||||
public static final String DEFAULT_KEY = "abcdefgh";
|
||||
|
||||
private static Log log = Logs.get();
|
||||
|
||||
public static String encrypt(String data) {
|
||||
return encrypt(data, DEFAULT_KEY);
|
||||
}
|
||||
|
||||
public static String decrypt(String data) {
|
||||
return decrypt(data, DEFAULT_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description 根据键值进行加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param key 加密键byte数组
|
||||
* @return 密文
|
||||
*/
|
||||
public static String encrypt(String data, String key) {
|
||||
byte[] bt = null;
|
||||
try {
|
||||
bt = encrypt(data.getBytes(), key.getBytes());
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
return Base64.encodeToString(bt, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description 根据键值进行解密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param key 加密键byte数组
|
||||
* @return 明文
|
||||
*/
|
||||
public static String decrypt(String data, String key) {
|
||||
if (data == null)
|
||||
{return null;}
|
||||
|
||||
byte[] buf = Base64.decode(data);
|
||||
byte[] bt = null;
|
||||
try {
|
||||
bt = decrypt(buf, key.getBytes());
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
return new String(bt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description 根据键值进行加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param key 加密键byte数组
|
||||
* @return 密文
|
||||
* @throws InvalidKeyException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws NoSuchPaddingException
|
||||
* @throws InvalidKeySpecException
|
||||
* @throws BadPaddingException
|
||||
* @throws IllegalBlockSizeException
|
||||
*/
|
||||
private static byte[] encrypt(byte[] data, byte[] key) throws InvalidKeyException, NoSuchAlgorithmException,
|
||||
NoSuchPaddingException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException {
|
||||
SecureRandom sr = new SecureRandom();
|
||||
|
||||
DESKeySpec dks = new DESKeySpec(key);
|
||||
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_NAME);
|
||||
SecretKey securekey = keyFactory.generateSecret(dks);
|
||||
|
||||
Cipher cipher = Cipher.getInstance(DES_NAME);
|
||||
|
||||
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
|
||||
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description 根据键值进行解密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param key 加密键byte数组
|
||||
* @return 明文
|
||||
* @throws InvalidKeyException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws InvalidKeySpecException
|
||||
* @throws NoSuchPaddingException
|
||||
* @throws BadPaddingException
|
||||
* @throws IllegalBlockSizeException
|
||||
*/
|
||||
private static byte[] decrypt(byte[] data, byte[] key) throws InvalidKeyException, NoSuchAlgorithmException,
|
||||
InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
|
||||
SecureRandom sr = new SecureRandom();
|
||||
|
||||
DESKeySpec dks = new DESKeySpec(key);
|
||||
|
||||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_NAME);
|
||||
SecretKey securekey = keyFactory.generateSecret(dks);
|
||||
|
||||
Cipher cipher = Cipher.getInstance(DES_NAME);
|
||||
|
||||
cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
|
||||
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
package com.sinosoft.cloud.plus.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.nutz.lang.Times;
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
*/
|
||||
public class DateUtils extends Times {
|
||||
|
||||
public static final String DATE_FORMAT_MONTH = "yyyy-MM";
|
||||
public static final String DATE_FORMAT_DAY = "yyyy-MM-dd";
|
||||
|
||||
/**
|
||||
* 日期加减
|
||||
*
|
||||
* @param base
|
||||
* 开始日期
|
||||
* @param days
|
||||
* 增加天数 正数为之后日期负数为之前日期
|
||||
* @return 目标日期
|
||||
*/
|
||||
public static Date addDays(Date base, int days) {
|
||||
return D(base.getTime() + days * 24 * 60 * 60 * 1000L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从今日开始的日期加减
|
||||
*
|
||||
* @param days
|
||||
* 增加天数 正数为之后日期负数为之前日期
|
||||
* @return 目标日期
|
||||
*/
|
||||
public static Date addDays(int days) {
|
||||
return addDays(now(), days);
|
||||
}
|
||||
|
||||
/**
|
||||
* 两个日期之间的天数差
|
||||
*
|
||||
* @param start
|
||||
* 开始日期
|
||||
* @param end
|
||||
* 结束日期
|
||||
* @return 天数
|
||||
*/
|
||||
public static double daysBetween(Date start, Date end) {
|
||||
return BigDecimal.valueOf((end.getTime() - start.getTime()) / 1000.0d / 24.0d / 60.0d / 60.0d)
|
||||
.setScale(0, RoundingMode.HALF_UP)
|
||||
.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当日凌晨
|
||||
*
|
||||
* @param d
|
||||
* 日期
|
||||
* @return 当日凌晨 date 对象
|
||||
*/
|
||||
public static Date getDayStart(Date d) {
|
||||
return D(format("yyyy-MM-dd 00:00:00", d));
|
||||
}
|
||||
|
||||
public static Date getDayEnd(Date d) {
|
||||
return D(format("yyyy-MM-dd 23:59:59", d));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取今日凌晨
|
||||
*
|
||||
* @return 今日凌晨0:0:0的时间实例
|
||||
*/
|
||||
public static Date getDayStart() {
|
||||
return D(format("yyyy-MM-dd 00:00:00", now()));
|
||||
}
|
||||
|
||||
public static Date getDayEnd() {
|
||||
return D(format("yyyy-MM-dd 23:59:59", now()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期的周结束(周日或者周六)
|
||||
*
|
||||
* @param startFromSunday
|
||||
* 从周日开始计算周 标识
|
||||
* @return startFromSunday 为true 则返回下一个周六 为false则返回下一个周日
|
||||
*/
|
||||
public static Date getWeekEnd(boolean startFromSunday) {
|
||||
Date date = addDays(getWeekStart(startFromSunday), 6);
|
||||
return getDayEnd(date);
|
||||
}
|
||||
|
||||
public static Date getWeekEnd(boolean startFromSunday, Date date) {
|
||||
Date newDate = addDays(getWeekStart(startFromSunday, date), 6);
|
||||
return getDayEnd(newDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期的周开始(周一或者周日)
|
||||
*
|
||||
* @param startFromSunday
|
||||
* 从周日开始计算周 标识
|
||||
* @return startFromSunday 为true 则返回上一个周日 为false则返回上一个周一
|
||||
*/
|
||||
public static Date getWeekStart(boolean startFromSunday) {
|
||||
return addDays(getDayStart(),
|
||||
-1
|
||||
* (Times.C(now()).get(Calendar.DAY_OF_WEEK)
|
||||
- 1
|
||||
- (startFromSunday ? 0 : 1)));
|
||||
}
|
||||
|
||||
public static Date getWeekStart(boolean startFromSunday, Date date) {
|
||||
return addDays(getDayStart(date),
|
||||
-1
|
||||
* (Times.C(now()).get(Calendar.DAY_OF_WEEK)
|
||||
- 1
|
||||
- (startFromSunday ? 0 : 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加秒
|
||||
*
|
||||
* @param base
|
||||
* 基础时间
|
||||
* @param seconds
|
||||
* 秒数
|
||||
* @return 日期对象
|
||||
*/
|
||||
public static Date addSeconds(Date base, long seconds) {
|
||||
return D(base.getTime() + seconds * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加秒
|
||||
*
|
||||
* @param seconds
|
||||
* 秒数
|
||||
* @return 日期对象
|
||||
*/
|
||||
public static Date addSeconds(long seconds) {
|
||||
return addSeconds(now(), seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取元旦日期
|
||||
*
|
||||
* @param d
|
||||
* 日期
|
||||
* @return 元旦日期
|
||||
*/
|
||||
public static Date getYearStart(Date d) {
|
||||
String year = format("yyyy", d);
|
||||
year += "-01-01";
|
||||
return D(year);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取元旦日期
|
||||
*
|
||||
* @return 元旦日期
|
||||
*/
|
||||
public static Date getYearStart() {
|
||||
return getYearStart(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取年末日期
|
||||
*
|
||||
* @param d
|
||||
* 日期
|
||||
* @return 年末日期
|
||||
*/
|
||||
public static Date getYearEnd(Date d) {
|
||||
String year = format("yyyy", d);
|
||||
year += "-12-31";
|
||||
return getDayEnd(D(year));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取年末日期
|
||||
*
|
||||
* @return 年末日期
|
||||
*/
|
||||
public static Date getYearEnd() {
|
||||
return getYearEnd(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月初日期
|
||||
*
|
||||
* @param d
|
||||
* 日期
|
||||
* @return 月初日期
|
||||
*/
|
||||
public static Date getMonthStart(Date d) {
|
||||
String month = format(DATE_FORMAT_MONTH, d) + "-01";
|
||||
return D(month);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月初日期
|
||||
*
|
||||
* @return 月初日期
|
||||
*/
|
||||
public static Date getMonthStart() {
|
||||
return getMonthStart(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月末日期
|
||||
*
|
||||
* @param d
|
||||
* 日期
|
||||
* @return 月末日期
|
||||
*/
|
||||
public static Date getMonthEnd(Date d) {
|
||||
Calendar ca = Calendar.getInstance();
|
||||
ca.setTime(d);
|
||||
ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
return getDayEnd(ca.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月末日期
|
||||
*
|
||||
* @return 月末日期
|
||||
*/
|
||||
public static Date getMonthEnd() {
|
||||
return getMonthEnd(now());
|
||||
}
|
||||
|
||||
// 获取时间相关序列
|
||||
public static String getSequence() {
|
||||
String sequence = format("yyyyMMDD", now());
|
||||
sequence += ms() % 10000;
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public static String getYearStartMonth() {
|
||||
return format(DATE_FORMAT_MONTH, getYearStart());
|
||||
}
|
||||
|
||||
public static String getYearStartMonth(Date date) {
|
||||
return format(DATE_FORMAT_MONTH, getYearStart(date));
|
||||
}
|
||||
|
||||
public static String getYearEndMonth() {
|
||||
return format(DATE_FORMAT_MONTH, getYearEnd());
|
||||
}
|
||||
|
||||
public static String getYearEndMonth(Date date) {
|
||||
return format(DATE_FORMAT_MONTH, getYearEnd(date));
|
||||
}
|
||||
|
||||
public static String getMonthStartDate() {
|
||||
return format(DATE_FORMAT_DAY, getMonthStart());
|
||||
}
|
||||
|
||||
public static String getMonthStartDate(Date date) {
|
||||
return format(DATE_FORMAT_DAY, getMonthStart(date));
|
||||
}
|
||||
|
||||
public static String getMonthEndDate() {
|
||||
return format(DATE_FORMAT_DAY, getMonthEnd());
|
||||
}
|
||||
|
||||
public static String getMonthEndDate(Date date) {
|
||||
return format(DATE_FORMAT_DAY, getMonthEnd(date));
|
||||
}
|
||||
|
||||
public static int getDayOfMonth() {
|
||||
return Calendar.getInstance(Locale.CHINA).getActualMaximum(Calendar.DATE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
package com.sinosoft.cloud.plus.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import org.nutz.lang.Files;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
|
||||
/**
|
||||
* @author zhaodonghai@sinosoft.com.cn
|
||||
* @since 2020-10-23
|
||||
*/
|
||||
public class FileUtils {
|
||||
private FileUtils() {}
|
||||
|
||||
/**
|
||||
* 清除SVN
|
||||
*
|
||||
* @param dir
|
||||
* 待清除的目录
|
||||
* @return 清除成功状态标识
|
||||
*/
|
||||
public static boolean cleanSvn(File dir) {
|
||||
try {
|
||||
Files.cleanAllFolderInSubFolderes(dir, ".svn");
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除项目下的文件
|
||||
*
|
||||
* @param dir
|
||||
* 根目录
|
||||
* @param name
|
||||
* 文件名
|
||||
* @throws IOException
|
||||
* 删除失败时
|
||||
*/
|
||||
public static void cleanAllFileInSubFolderes(File dir, String name) throws IOException {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (File d : files) {
|
||||
if (!d.isDirectory() && d.getName().equalsIgnoreCase(name))
|
||||
{
|
||||
Files.deleteFile(d);
|
||||
}
|
||||
else if (d.isDirectory())
|
||||
{ cleanAllFileInSubFolderes(d, name);}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理项目
|
||||
*
|
||||
* @param dir
|
||||
* 项目根目录
|
||||
*/
|
||||
public static void cleanProject(String dir) {
|
||||
cleanProject(Files.checkFile(dir), ".project", ".settings", ".idea", ".vscode", ".classpath", ".factorypath", "target");
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理项目
|
||||
*
|
||||
* @param dir
|
||||
* 项目根目录
|
||||
*/
|
||||
public static void cleanProject(File dir) {
|
||||
cleanProject(dir, ".project", ".settings", ".idea", ".vscode", ".classpath", ".factorypath", "target");
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理项目
|
||||
*
|
||||
* @param dir
|
||||
* 项目根目录
|
||||
* @param files
|
||||
* 待清除文件
|
||||
*/
|
||||
public static void cleanProject(File dir, String... files) {
|
||||
Lang.list(files).stream().forEach(item -> {
|
||||
try {
|
||||
Files.cleanAllFolderInSubFolderes(dir, item);
|
||||
cleanAllFileInSubFolderes(dir, item);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计文件或者目录下的java代码的行数
|
||||
*
|
||||
* @param file
|
||||
* 文件或者目录
|
||||
* @return java代码行数
|
||||
*/
|
||||
public static long countJavaCodeLines(File file) {
|
||||
return countLines(file, ".java");
|
||||
}
|
||||
|
||||
public static double getDirSize(File file) {
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
File[] children = file.listFiles();
|
||||
double size = 0;
|
||||
for (File f : children) {
|
||||
size += getDirSize(f);
|
||||
}
|
||||
return size;
|
||||
} else {
|
||||
return file.length();
|
||||
}
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换文件大小
|
||||
*
|
||||
* @param length
|
||||
* 文件长度
|
||||
* @return 文件大小字串描述
|
||||
*/
|
||||
public static String formetFileSize(double length) {
|
||||
DecimalFormat df = new DecimalFormat("#.00");
|
||||
String fileSizeString = "";
|
||||
if (length < 1024) {
|
||||
fileSizeString = df.format(length) + "B";
|
||||
} else if (length < 1048576) {
|
||||
fileSizeString = df.format(length / 1024) + "K";
|
||||
} else if (length < 1073741824) {
|
||||
fileSizeString = df.format(length / 1048576) + "M";
|
||||
} else {
|
||||
fileSizeString = df.format(length / 1073741824) + "G";
|
||||
}
|
||||
return fileSizeString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算文件行数
|
||||
*
|
||||
* @param file
|
||||
* 文件(非目录类型)
|
||||
* @return 行数
|
||||
*/
|
||||
public static long countLine(File file) {
|
||||
long target = 0;
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
log.debug(line);
|
||||
target++;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计文件或者目录下的指定类型文件的行数
|
||||
*
|
||||
* @param file
|
||||
* 文件或者目录
|
||||
* @param suf
|
||||
* 扩展名
|
||||
* @return 行数
|
||||
*/
|
||||
public static long countLines(File file, String suf) {
|
||||
long target = 0;
|
||||
if (file.isFile() && file.getName().endsWith(suf)) {
|
||||
return countLine(file);
|
||||
} else if (file.isFile()) {
|
||||
return 0;
|
||||
} else if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
for (File f : files) {
|
||||
target += countLines(f, suf);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速查找
|
||||
*
|
||||
* @param dir
|
||||
* 基目录
|
||||
* @param name
|
||||
* 待查找文件名
|
||||
* @return 文件
|
||||
*/
|
||||
public static File fastFindFile(File dir, String name) {
|
||||
return fastFindFile(dir, name, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速查找文件
|
||||
*
|
||||
* @param dir
|
||||
* 基目录
|
||||
* @param name
|
||||
* 文件名
|
||||
* @param method
|
||||
* 查找方法 1 全等查询 2 模糊查找 3 忽略大小写全等 4忽略大小写模糊
|
||||
* @return 文件
|
||||
*/
|
||||
public static File fastFindFile(File dir, String name, int method) {
|
||||
File target = null;
|
||||
File[] dirs = Files.dirs(dir);// 获取目录
|
||||
File[] files = Files.files(dir, name);// 获取文件
|
||||
// 优先扫描文件
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (matchs(file.getName(), name, method)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 然后扫目录
|
||||
if (dirs != null) {
|
||||
for (File file : dirs) {
|
||||
target = fastFindFile(file, name, method);
|
||||
if (target != null) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private static boolean matchs(String fileName, String name, int method) {
|
||||
switch (method) {
|
||||
case 1:
|
||||
return Strings.equals(fileName, name);
|
||||
case 2:
|
||||
return fileName.endsWith(name);
|
||||
case 3:
|
||||
return Strings.equals(fileName.toUpperCase(), name.toUpperCase());
|
||||
default:
|
||||
return fileName.toUpperCase().endsWith(name.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
public static File fastFindFile(String dir, String name) {
|
||||
return fastFindFile(new File(dir), name, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速查找
|
||||
*
|
||||
* @param dir
|
||||
* 基目录
|
||||
* @param name
|
||||
* 待查找文件名
|
||||
* @return 文件
|
||||
*/
|
||||
public static File fastFindFileLikeName(File dir, String name) {
|
||||
return fastFindFile(dir, name, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 基本实现 文件查找
|
||||
*
|
||||
* @param dir
|
||||
* 查找的开始位置
|
||||
* @param name
|
||||
* 查找的文件的名字
|
||||
* @return 文件
|
||||
*/
|
||||
public static File findFile(File dir, String name) {
|
||||
File target = null;
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isFile() && Strings.equals(file.getName(), name)) {
|
||||
return file;
|
||||
} else if (file.isDirectory()) {
|
||||
target = findFile(file, name);
|
||||
if (target != null) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||