Former-commit-id: 5bb8ebb5dadd747fc00a4b3d4195d627c7ba1131
master
wangbing 4 years ago
parent e1026c8002
commit cdc4a479c3

@ -139,12 +139,6 @@
<!--<systemPath>${project.basedir}/src/main/resources/lib/ojdbc7-12.1.0.2.jar</systemPath>-->
<!--</dependency>-->
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>

@ -23,11 +23,11 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import xyz.wbsite.dbtool.web.config.ActionConfig;
import xyz.wbsite.dbtool.web.frame.auth.LocalData;
import xyz.wbsite.dbtool.web.frame.auth.Token;
import xyz.wbsite.dbtool.web.frame.base.BaseRequest;
import xyz.wbsite.dbtool.web.frame.base.BaseResponse;
import xyz.wbsite.dbtool.web.frame.base.ErrorType;
import xyz.wbsite.dbtool.web.frame.base.Screen;
import xyz.wbsite.dbtool.web.frame.base.Token;
import xyz.wbsite.dbtool.web.frame.utils.MapperUtil;
import javax.servlet.http.HttpServletRequest;

@ -3,6 +3,7 @@ package xyz.wbsite.dbtool.web.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@ -12,7 +13,6 @@ import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import xyz.wbsite.dbtool.web.frame.auth.LocalData;
import xyz.wbsite.dbtool.web.frame.base.Token;
import xyz.wbsite.dbtool.web.frame.utils.CookieUtil;
import javax.servlet.Filter;
@ -21,6 +21,7 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -35,6 +36,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
private String[] excluded;
@Value("${spring.mvc.static-path-pattern}")
private String[] staticPath;
@Value("${web.url.login}")
private String loginPage;
@Override
public void configure(WebSecurity web) throws Exception {
@ -72,35 +75,38 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String token = request.getParameter("token");
if (token == null || token.isEmpty()) {
token = CookieUtil.getCookieValue(request.getCookies(), "token");
}
if (token == null) {
LocalData.setToken(LocalData.getTempToken());
} else {
// 组装Token ~ 这边根据实际的业务组装Token
Token token1 = new Token();
token1.setId(1L);
token1.setUserId(1L);
token1.setUserName("admin");
//继承临时Token
token1.addResourceSet(LocalData.getTempToken());
//管理员特有资源(这边请用正则表达式)
token1.putResource(".*");
LocalData.setToken(token1);
}
// 组装Token ~ 这边根据实际的业务组装Token
// if (token != null) {
// TokensManager tokensManager = LocalData.getBean(TokensManager.class);
// TokensBuildRequest tokensBuildRequest = new TokensBuildRequest();
// tokensBuildRequest.setToken(token);
// TokensBuildResponse tokensBuildResponse = tokensManager.build(tokensBuildRequest, LocalData.getSysToken());
// LocalData.setToken(tokensBuildResponse.getToken());
// } else {
// LocalData.setToken(null);
// }
// Action
String servletPath = request.getServletPath();
String servletPath = request.getServletPath().toLowerCase();
Pattern compile = Pattern.compile("^/(.+)\\.htm");
Matcher matcher = compile.matcher(servletPath);
if (matcher.find()) {
LocalData.setAction(matcher.group(1));
}
filterChain.doFilter(servletRequest, servletResponse);
try {
filterChain.doFilter(servletRequest, servletResponse);
} catch (AccessDeniedException e) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
} catch (Exception e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
}
@ -108,16 +114,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
public Object getAuthorization() {
return new Object() {
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
// 授权
Token token_ = LocalData.getToken();
if (token_.hasResource(request.getServletPath())) {
return true;
}
return false;
return true;
}
};
}
}

@ -1,10 +1,10 @@
package xyz.wbsite.dbtool.web.frame.auth;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;
import xyz.wbsite.dbtool.web.frame.base.Token;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -18,26 +18,16 @@ import javax.servlet.http.HttpServletResponse;
*/
public class LocalData {
private static Token temp = null;
private static ApplicationContext applicationContext = null;
private static Token system = null;
static {
// 组装临时Token和系统Token
temp = new Token();
temp.setId(-1);
temp.setUserId(-1);
temp.setUserName("游客");
temp.putResource("ajax.system.admin.login");
// 组装系统Token
system = new Token();
system.setId(0);
system.setUserId(0);
system.setUserName("system");
system.putResource(".*");
}
public static Token getTempToken() {
return temp;
}
public static Token getSysToken() {
@ -79,6 +69,30 @@ public class LocalData {
}
public static ApplicationContext getApplicationContext() {
return WebApplicationContextUtils.getWebApplicationContext(getRequest().getServletContext());
return LocalData.applicationContext;
}
public static void setApplicationContext(ApplicationContext applicationContext) {
LocalData.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> t) {
if (getApplicationContext() == null) {
return null;
}
try {
return getApplicationContext().getBean(t);
} catch (BeansException ignored) {
return null;
}
}
public static Environment getEnvironment() {
return getBean(Environment.class);
}
public static String getActive() {
String[] profiles = getEnvironment().getActiveProfiles();
return String.join(",", profiles);
}
}

@ -1,4 +1,4 @@
package xyz.wbsite.dbtool.web.frame.base;
package xyz.wbsite.dbtool.web.frame.auth;
import java.io.Serializable;
import java.util.HashSet;
@ -17,6 +17,10 @@ public class Token implements Serializable {
* ID
*/
private long id;
/**
* TOKEN
*/
private String token;
/**
* ID
*/
@ -26,8 +30,15 @@ public class Token implements Serializable {
*/
private String userName;
private Set<String> resourceSet = new HashSet<>();
private Set<String> resSet = new HashSet<>();
public boolean hasRes(String res) {
return true;
}
public Set<String> getResSet() {
return resSet;
}
public long getId() {
return id;
@ -53,28 +64,11 @@ public class Token implements Serializable {
this.userName = userName;
}
public boolean hasResource(String resource) {
for (String s : resourceSet) {
if (resource.matches(s)) {
return true;
}
}
return false;
}
public void putResource(String resource) {
resourceSet.add(resource);
}
public Set<String> getResourceSet() {
return resourceSet;
}
public void addResourceSet(Set<String> resourceSet) {
this.resourceSet.addAll(resourceSet);
public String getToken() {
return token;
}
public void addResourceSet(Token token) {
addResourceSet(token.getResourceSet());
public void setToken(String token) {
this.token = token;
}
}

@ -1,17 +0,0 @@
package xyz.wbsite.dbtool.web.frame.auth;
import xyz.wbsite.dbtool.web.frame.validation.DictValidator;
import javax.validation.Constraint;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DictValidator.class)
public @interface Verification {
String name() default "";
}

@ -12,9 +12,13 @@ import java.util.Date;
* @version 0.0.1
* @since 2017-01-01
*/
public class BaseEntity implements Serializable {
/**
*
*/
private long id;
/**
*
*/
@ -44,19 +48,11 @@ public class BaseEntity implements Serializable {
private Date lastUpdateTime;
/**
*
*/
*
*/
@JsonIgnore
private boolean isDeleted;
public boolean getIsDeleted() {
return isDeleted;
}
public void setIsDeleted(boolean isDeleted) {
this.isDeleted = isDeleted;
}
public long getRowVersion() {
return rowVersion;
}
@ -65,20 +61,20 @@ public class BaseEntity implements Serializable {
this.rowVersion = rowVersion;
}
public long getCreateBy() {
return createBy;
public long getId() {
return id;
}
public void setCreateBy(long createBy) {
this.createBy = createBy;
public void setId(long id) {
this.id = id;
}
public long getLastUpdateBy() {
return lastUpdateBy;
public long getCreateBy() {
return createBy;
}
public void setLastUpdateBy(long lastUpdateBy) {
this.lastUpdateBy = lastUpdateBy;
public void setCreateBy(long createBy) {
this.createBy = createBy;
}
public Date getCreateTime() {
@ -89,6 +85,14 @@ public class BaseEntity implements Serializable {
this.createTime = createTime;
}
public long getLastUpdateBy() {
return lastUpdateBy;
}
public void setLastUpdateBy(long lastUpdateBy) {
this.lastUpdateBy = lastUpdateBy;
}
public Date getLastUpdateTime() {
return lastUpdateTime;
}
@ -96,4 +100,12 @@ public class BaseEntity implements Serializable {
public void setLastUpdateTime(Date lastUpdateTime) {
this.lastUpdateTime = lastUpdateTime;
}
public boolean getIsDeleted() {
return isDeleted;
}
public void setIsDeleted(boolean deleted) {
isDeleted = deleted;
}
}

@ -8,9 +8,13 @@ package xyz.wbsite.dbtool.web.frame.base;
* @since 2017-01-01
*/
public class BaseFindRequest extends BaseRequest {
private int pageNumber = 1;
private int pageSize = 10;
private String sortKey;
private SortType sortType;
public int getPageNumber() {
@ -44,4 +48,5 @@ public class BaseFindRequest extends BaseRequest {
public void setSortType(SortType sortType) {
this.sortType = sortType;
}
}

@ -9,7 +9,7 @@ import java.util.List;
* @version 0.0.1
* @since 2017-01-01
*/
public class BaseFindResponse<T> extends BaseResponse {
public class BaseFindResponse<T> extends BaseResponse{
private List<T> result;

@ -11,28 +11,28 @@ import java.util.List;
* @since 2017-01-01
*/
public class BaseResponse {
private List<xyz.wbsite.dbtool.web.frame.base.Error> errors = new ArrayList();
private List<Error> errors = new ArrayList();
public void addError(xyz.wbsite.dbtool.web.frame.base.Error error) {
public void addError(Error error){
this.errors.add(error);
}
public void addError(ErrorType type, String message) {
this.errors.add(new xyz.wbsite.dbtool.web.frame.base.Error(type, message));
public void addError(ErrorType type,String message){
this.errors.add(new Error(type,message));
}
public void addErrors(List<xyz.wbsite.dbtool.web.frame.base.Error> errors) {
public void addErrors(List<Error> errors){
this.errors.addAll(errors);
}
public boolean hasError() {
public boolean hasError(){
return this.errors.size() > 0;
}
/**
*
*/
public List<xyz.wbsite.dbtool.web.frame.base.Error> getErrors() {
return new ArrayList<xyz.wbsite.dbtool.web.frame.base.Error>(errors);
public List<Error> getErrors() {
return new ArrayList<Error>(errors);
}
}

@ -10,8 +10,8 @@ package xyz.wbsite.dbtool.web.frame.base;
public class BaseSearchRequest extends BaseFindRequest {
/**
*
*/
*
*/
private String keyword;
public String getKeyword() {

@ -7,11 +7,11 @@ package xyz.wbsite.dbtool.web.frame.base;
* @version 0.0.1
* @since 2017-01-01
*/
public class BaseUpdateRequest extends BaseRequest {
public class BaseUpdateRequest extends BaseRequest{
/**
*
*/
*
*/
private long rowVersion;
public long getRowVersion() {

@ -0,0 +1,18 @@
package xyz.wbsite.dbtool.web.frame.schedule;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.util.Assert;
import java.util.concurrent.ScheduledFuture;
public abstract class RunCronTask extends RunTask {
public abstract String cron();
@Override
public ScheduledFuture<?> schedule(ThreadPoolTaskScheduler poolTaskScheduler) {
Assert.notNull(poolTaskScheduler, "ThreadPoolTaskScheduler must not be null");
return poolTaskScheduler.schedule(this, new CronTrigger(cron()));
}
}

@ -0,0 +1,18 @@
package xyz.wbsite.dbtool.web.frame.schedule;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.Assert;
import java.time.Duration;
import java.util.concurrent.ScheduledFuture;
public abstract class RunDelayRepeatTask extends RunTask {
public abstract Duration interval();
@Override
public ScheduledFuture<?> schedule(ThreadPoolTaskScheduler poolTaskScheduler) {
Assert.notNull(poolTaskScheduler, "ThreadPoolTaskScheduler must not be null");
return poolTaskScheduler.scheduleWithFixedDelay(this, interval());
}
}

@ -0,0 +1,18 @@
package xyz.wbsite.dbtool.web.frame.schedule;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.Assert;
import java.time.Duration;
import java.util.concurrent.ScheduledFuture;
public abstract class RunFixRepeatTask extends RunTask {
public abstract Duration interval();
@Override
public ScheduledFuture<?> schedule(ThreadPoolTaskScheduler poolTaskScheduler) {
Assert.notNull(poolTaskScheduler, "ThreadPoolTaskScheduler must not be null");
return poolTaskScheduler.scheduleAtFixedRate(this, interval());
}
}

@ -0,0 +1,29 @@
package xyz.wbsite.dbtool.web.frame.schedule;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
public abstract class RunTask implements Runnable {
public abstract String taskId();
public String taskName(){
return "";
}
public String taskNote(){
return "";
}
public abstract ScheduledFuture<?> schedule(ThreadPoolTaskScheduler poolTaskScheduler);
public void configChange(ThreadPoolTaskScheduler scheduler) {
ScheduledFuture<?> schedule = scheduler.schedule(this, new Date());
if (!schedule.cancel(true)) {
}
}
}

@ -0,0 +1,86 @@
package xyz.wbsite.dbtool.web.frame.schedule;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.ErrorHandler;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Scheduler extends ThreadPoolTaskScheduler implements ErrorHandler {
private Map<String, TaskWrapper> taskMap = new HashMap<>();
public Scheduler() {
setErrorHandler(this);
setPoolSize(4);
initialize();
}
public boolean createOrRepeat(RunTask task) {
if (taskMap.containsKey(task.taskId())) {
ScheduledFuture<?> scheduledFuture = taskMap.get(task.taskId()).future;
scheduledFuture.cancel(false);
}
taskMap.put(task.taskId(), new TaskWrapper(task));
return true;
}
public boolean remove(String taskId) {
if (taskMap.containsKey(taskId)) {
ScheduledFuture<?> scheduledFuture = taskMap.get(taskId).future;
scheduledFuture.cancel(false);
taskMap.remove(taskId);
}
return true;
}
public boolean start(String taskId) {
if (taskMap.containsKey(taskId)) {
taskMap.get(taskId).run = true;
taskMap.get(taskId).future = taskMap.get(taskId).target.schedule(this);
return true;
}
return false;
}
public boolean stop(String taskId) {
if (taskMap.containsKey(taskId)) {
taskMap.get(taskId).run = false;
ScheduledFuture<?> scheduledFuture = taskMap.get(taskId).future;
scheduledFuture.cancel(false);
return true;
}
return false;
}
@Override
public void handleError(Throwable throwable) {
String message = throwable.getMessage();
Pattern compile = Pattern.compile("(\\[.*])执行异常任务ID(\\(.*\\))");
Matcher matcher = compile.matcher(message);
if (matcher.find()) {
}
}
class TaskWrapper {
RunTask target;
String taskId;
String taskName;
String taskNote;
boolean run;
ScheduledFuture<?> future;
public TaskWrapper(RunTask runTask) {
this.target = runTask;
this.taskId = runTask.taskId();
this.taskName = runTask.taskName();
this.taskNote = runTask.taskNote();
this.future = runTask.schedule(Scheduler.this);
this.run = true;
}
}
}

@ -3,7 +3,9 @@ package xyz.wbsite.dbtool.web.frame.utils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
@ -21,6 +23,22 @@ public class AESUtil {
private static final String ALGORITHM = "AES";
private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";
public static String generateDesKey() {
try {
//实例化
KeyGenerator kgen = null;
kgen = KeyGenerator.getInstance("AES");
//设置密钥长度
kgen.init(128);
//生成密钥
SecretKey skey = kgen.generateKey();
//返回密钥的二进制编码
return BytesUtil.bytes2Hex(skey.getEncoded());
} catch (NoSuchAlgorithmException e) {
return "";
}
}
/**
*
*
@ -30,10 +48,10 @@ public class AESUtil {
*/
public static byte[] encrypt(byte[] data, String secret) {
try {
if (secret.length() != 16) {
throw new IllegalArgumentException("secret's length is not 16");
if (secret.length() != 32) {
throw new IllegalArgumentException("Hex secret's length must be 32");
}
SecretKeySpec key = new SecretKeySpec(secret.getBytes(), ALGORITHM);
SecretKeySpec key = new SecretKeySpec(BytesUtil.hex2Bytes(secret), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM_STR); // 创建密码器
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
return cipher.doFinal(data);// 加密
@ -72,10 +90,10 @@ public class AESUtil {
*/
public static byte[] decrypt(byte[] data, String secret) {
try {
if (secret.length() != 16) {
throw new IllegalArgumentException("secret's length is not 16");
if (secret.length() != 32) {
throw new IllegalArgumentException("Hex secret's length must be 32");
}
SecretKeySpec key = new SecretKeySpec(secret.getBytes(), ALGORITHM);
SecretKeySpec key = new SecretKeySpec(BytesUtil.hex2Bytes(secret), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);

@ -1,7 +1,5 @@
package xyz.wbsite.dbtool.web.frame.utils;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
/**
@ -496,20 +494,4 @@ public class Base64Util {
return dArr;
}
public static void main(String[] args) throws IOException {
try {
byte[] bytes = FileUtil.readFileToByteArray(new File("E:\\patt.png"));
String string = Base64Util.encodeToString(bytes);
System.out.println(string);
} catch (IOException e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,54 @@
package xyz.wbsite.dbtool.web.frame.utils;
/**
* BytesUtil -
*
* @author wangbing
* @version 0.0.1
* @since 2017-01-01
*/
public class BytesUtil {
private static final char[] HEXES = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f'
};
/**
* byte16
*/
public static String bytes2Hex(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return null;
}
StringBuilder hex = new StringBuilder();
for (byte b : bytes) {
hex.append(HEXES[(b >> 4) & 0x0F]);
hex.append(HEXES[b & 0x0F]);
}
return hex.toString();
}
/**
* 16byte
*/
public static byte[] hex2Bytes(String hex) {
if (hex == null || hex.length() == 0) {
return null;
}
char[] hexChars = hex.toCharArray();
byte[] bytes = new byte[hexChars.length / 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16);
}
return bytes;
}
}

@ -4,6 +4,7 @@ import xyz.wbsite.dbtool.web.frame.auth.LocalData;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* CookieUtil
@ -38,14 +39,30 @@ public class CookieUtil {
/**
* Cookie
*
* @param cookies Cookies
* @return passportID
* @param name
* @param value
*/
public static Cookie newCookie(String key, String value) {
public static Cookie newCookie(String name, String value) {
HttpServletRequest request = LocalData.getRequest();
Cookie cookie = new Cookie(key, value);
Cookie cookie = new Cookie(name, value);
cookie.setDomain(request.getServerName());
cookie.setPath(request.getContextPath());
cookie.setMaxAge(-1);
cookie.setPath("/");
return cookie;
}
}
/**
* Cookie
*
* @param name
*/
public static void clearCookie(String name) {
HttpServletRequest request = LocalData.getRequest();
HttpServletResponse response = LocalData.getResponse();
Cookie cookie = new Cookie(name, null);
cookie.setDomain(request.getServerName());
cookie.setMaxAge(0);
cookie.setPath("/");
response.addCookie(cookie);
}
}

@ -16,6 +16,38 @@ import java.util.List;
public class FileUtil {
public static List<String> readFileToLines(File filePath) {
return readFileToLines(filePath.getAbsoluteFile());
}
public static List<String> readFileToLines(String fileName) {
List<String> returnString = new ArrayList<String>();
File file = new File(fileName);
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 1;
// 一次读入一行直到读入null为文件结束
while ((tempString = reader.readLine()) != null) {
// 显示行号
returnString.add(tempString);
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
}
}
}
return returnString;
}
public static String readFileToString(File file) throws IOException {
byte[] bytes = readFileToByteArray(file);
return new String(bytes, "UTF-8");
@ -50,28 +82,6 @@ public class FileUtil {
return var5;
}
public static List<String> readFileToLines(File file) {
List<String> stringLines = new ArrayList<String>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String line = null;
while ((line = reader.readLine()) != null) {
stringLines.add(line);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception ignored) {
}
}
return stringLines;
}
public static boolean writeStringToFile(String data, File file, boolean isNewLine, boolean isAppend) {
PrintWriter printWriter = null;
try {

@ -1,20 +0,0 @@
package xyz.wbsite.dbtool.web.frame.utils;
public class Formatter {
public static String formatJava(String content) {
// 聚合
content = content.replaceAll("\\s+|\\n", " ");
content = content.replaceAll(";\\s", ";");
content = content.replaceAll("\\s?\\{\\s?", "{");
content = content.replaceAll("\\s?}\\s?", "}");
content = content.replaceAll("\\*/\\s?", "\\*/");
//分散
content = content.replaceAll("\\*/", "*/\n");
content = content.replaceAll(";", ";\n");
content = content.replaceAll("\\{", "\n{\n");
content = content.replaceAll("}", "}\n");
return content;
}
}

@ -1,5 +1,7 @@
package xyz.wbsite.dbtool.web.frame.utils;
import java.util.UUID;
/**
* IDgenerator - ID
*
@ -66,4 +68,8 @@ public class IDgenerator {
protected static long timeGen() {
return System.currentTimeMillis();
}
public static String nextUUID() {
return UUID.randomUUID().toString();
}
}

@ -17,44 +17,40 @@ public class LogUtil {
/**
* info
*
* @param context
*/
public static void i(String context) {
public static void i(String context){
logger.info(context);
}
/**
* debug
*
* @param context
*/
public static void d(String context) {
public static void d(String context){
logger.debug(context);
}
/**
* warn
*
* @param context
*/
public static void w(String context) {
public static void w(String context){
logger.warn(context);
}
/**
* error
*
* @param context
*/
public static void e(String context) {
public static void e(String context){
logger.error(context);
}
/**
*
*/
public static void dumpException(Throwable e) {
public static void dumpException(Throwable e){
StringBuffer msg = new StringBuffer("null");
if (e != null) {
msg = new StringBuffer("");

@ -13,44 +13,61 @@ import java.security.NoSuchAlgorithmException;
public class MD5Util {
/**
*
*
*
* @param value
* @return
* @param value
* @param salts
* @return
*/
public static String generatePwd(String value, String... salts) {
String pwd = encode(value);
for (String s : salts) {
pwd = encode(s + value + s);
}
return pwd;
}
/**
*
*
* @param value
* @return
*/
public static String generatePwd(String value) {
return generatePwd(value, "MD5");
}
/**
*
*
* @param value
* @return Hex
*/
public static String encode(String value) {
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] e = md.digest(value.getBytes());
return toHexString(e);
return BytesUtil.bytes2Hex(e);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return value;
}
}
/**
*
*
* @param bytes
* @return Hex
*/
public static String encode(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] e = md.digest(bytes);
return toHexString(e);
return BytesUtil.bytes2Hex(e);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
}
private static String toHexString(byte bytes[]) {
StringBuilder hs = new StringBuilder();
String stmp = "";
for (int n = 0; n < bytes.length; n++) {
stmp = Integer.toHexString(bytes[n] & 0xff);
if (stmp.length() == 1)
hs.append("0").append(stmp);
else
hs.append(stmp);
}
return hs.toString();
}
}

@ -1,147 +0,0 @@
package xyz.wbsite.dbtool.web.frame.utils;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
/**
*
* <p>
* : 使
* <dependency>
* <groupId>javax.mail</groupId>
* <artifactId>mail</artifactId>
* <version>1.4.7</version>
* </dependency>
* <p>
* : JavaMailSenderSpringboot
* JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
* javaMailSender.setDefaultEncoding(UTF-8);
* javaMailSender.setHost(smtp.example.com);
* javaMailSender.setUsername(**@example.com);
* javaMailSender.setPassword(******);
* javaMailSender.setPort(25);
* <p>
*
* MailUtil.sendSimpleMail(javaMailSender, username, "**@example.com", "标题", "内容");
* <p>
* HTML
* String html = "<html><body><h2>HTML邮件内容</h2><br><marquee>飞机飞走了.。。o O 0 ○~~~~~~~</marquee></body></html>";
* MailUtil.sendHtmlMail(javaMailSender, username, "**@example.com", "给你的", html);
* <p>
*
* MailUtil.sendAttachmentsMail(javaMailSender, username, "**@example.com", "给你的", html, "E:\\1.jpg");
* <p>
* HTML<img>
* String resId = "id_001";
* String html2 = "<html><body><h2>html邮件内容</h2><br><img src=\'cid:" + resId + "\'></img></body></html>";
* MailUtil.sendInlineResourceMail(javaMailSender, username, "**@example.com", "标题", html2, "E:\\1.jpg", resId);
*/
public class MailUtil {
/**
*
*
* @param sender
* @param from
* @param to
* @param subject
* @param content
*/
public static void sendSimpleMail(JavaMailSender sender, String from, String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(content);
message.setFrom(from);
sender.send(message);
}
/**
* HTML
*
* @param sender
* @param from
* @param to
* @param subject
* @param content
*/
public static void sendHtmlMail(JavaMailSender sender, String from, String to, String subject, String content) {
MimeMessage message = sender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(to);
helper.setFrom(from);
helper.setSubject(subject);
helper.setText(content, true);
sender.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
}
/**
*
*
* @param sender
* @param from
* @param to
* @param subject
* @param content
* @param filePath
*/
public static void sendAttachmentsMail(JavaMailSender sender, String from, String to, String subject, String content, String filePath) {
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = null;
try {
helper = new MimeMessageHelper(message, true);
helper.setTo(to);
helper.setFrom(from);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = file.getFilename();
//此处可以添加多个附件
helper.addAttachment(fileName, file);
sender.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
}
/**
*
*
* @param sender
* @param from
* @param to
* @param subject
* @param content
* @param rscPath
* @param rscId ID
*/
public static void sendInlineResourceMail(JavaMailSender sender, String from, String to, String subject, String content, String rscPath, String rscId) {
MimeMessage message = sender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(to);
helper.setFrom(from);
helper.setSubject(subject);
helper.setText(content, true);
//可以添加多个图片
FileSystemResource res = new FileSystemResource(new File(rscPath));
helper.addInline(rscId, res);
sender.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
}
}

@ -11,9 +11,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
import xyz.wbsite.dbtool.web.frame.auth.LocalData;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.List;
/**
@ -28,16 +30,25 @@ public class MapperUtil {
private static Mapper mapper;
static {
//初始化
om = new ObjectMapper();
//序列化时忽略null属性
om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//序列化时排序
om.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
//反序列化是忽略多余字段
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//支持空类序列化时出错InvalidDefinitionException
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
try {// 优先获取SpringBoot默认配置
om = LocalData.getBean(ObjectMapper.class);
} catch (Exception e) {
e.printStackTrace();
}
if (null == om) {
//初始化
om = new ObjectMapper();
// 日期格式化
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//序列化时忽略null属性
om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//序列化时排序
om.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
//反序列化是忽略多余字段
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//支持空类序列化时出错InvalidDefinitionException
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
mapper = new DozerBeanMapper();
}

@ -1,6 +1,5 @@
package xyz.wbsite.dbtool.web.frame.utils;
/**
* Message -
*

@ -14,7 +14,6 @@ import java.io.InputStreamReader;
public class ProcessUtil {
/**
* windowsexe
*
* @param path exe
*/
public static void execExe(String path) {
@ -29,7 +28,6 @@ public class ProcessUtil {
/**
* windows
*
* @param path
*/
public static void execBat(String path) {
@ -44,7 +42,6 @@ public class ProcessUtil {
/**
* windows cmd
*
* @param command cmd
*/
public static String execCmd(String command) {
@ -54,7 +51,6 @@ public class ProcessUtil {
/**
*
*
* @param command cmd
*/
public static String exec(String command) {

@ -0,0 +1,79 @@
package xyz.wbsite.dbtool.web.frame.utils;
import javax.servlet.http.HttpServletRequest;
/**
* RequestUtil
*
* @author wangbing
* @version 0.0.1
* @since 2017-01-01
*/
public class RequestUtil {
/**
* 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)) {
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.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} else if (ip.length() > 15) {
String[] ips = ip.split(",");
for (int index = 0; index < ips.length; index++) {
String strIp = (String) ips[index];
if (!("unknown".equalsIgnoreCase(strIp))) {
ip = strIp;
break;
}
}
}
return ip;
}
/**
*
*
* @param request
* @return
*/
public static String getUserAgent(HttpServletRequest request) {
return request.getHeader("User-Agent");
}
/**
* URL
*
* @param request
* @return URL
*/
public static String getErrorUrl(HttpServletRequest request) {
if (request.getAttribute("javax.servlet.error.request_uri") != null) {
return (String) request.getAttribute("javax.servlet.error.request_uri");
} else {
return "";
}
}
}

@ -16,6 +16,13 @@ import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Resource
*
* @author wangbing
* @version 0.0.1
* @since 2017-01-01
*/
public class ResourceUtil extends ResourceUtils {
/**
@ -85,6 +92,11 @@ public class ResourceUtil extends ResourceUtils {
}
}
/**
* jar
*
* @return
*/
public static boolean copyResource2File(String resource, File file) {
InputStream resourceInput = getResourceInput(resource);
FileOutputStream fileOutputStream = null;
@ -107,6 +119,11 @@ public class ResourceUtil extends ResourceUtils {
return true;
}
/**
*
*
* @return
*/
public static byte[] getResourceBytes(String resource) {
InputStream is = null;
byte[] result = null;

@ -9,7 +9,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/**
* Base64Util
* ResponseUtil
*
* @author wangbing
* @version 0.0.1
@ -34,5 +34,4 @@ public class ResponseUtil {
return null;
}
}
}

@ -0,0 +1,129 @@
package xyz.wbsite.dbtool.web.frame.utils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import xyz.wbsite.dbtool.web.frame.auth.LocalData;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class SqlUtil {
public static void exec(String sql) {
SqlSession sqlSession = null;
try {
SqlSessionFactory factory = LocalData.getBean(SqlSessionFactory.class);
sqlSession = factory.openSession(true);
Connection connection = sqlSession.getConnection();
PreparedStatement statement = connection.prepareStatement(sql);
statement.execute();
} catch (SQLException e) {
throw new RuntimeException(String.format("[ %s ]执行错误!", sql));
} finally {
if (sqlSession != null) sqlSession.close();
}
}
public static int insert(String sql) {
return update(sql);
}
public static int delete(String sql) {
return update(sql);
}
public static int update(String sql) {
SqlSession sqlSession = null;
int result = 0;
try {
SqlSessionFactory factory = LocalData.getBean(SqlSessionFactory.class);
sqlSession = factory.openSession(true);
Connection connection = sqlSession.getConnection();
PreparedStatement statement = connection.prepareStatement(sql);
result = statement.executeUpdate();
statement.close();
connection.close();
} catch (SQLException e) {
throw new RuntimeException(String.format("[ %s ]执行错误!", sql));
} finally {
if (sqlSession != null) sqlSession.close();
}
return result;
}
public static <T> List<T> select(String sql, Class<T> t) {
List<T> result = new ArrayList<>();
try {
SqlSessionFactory factory = LocalData.getBean(SqlSessionFactory.class);
SqlSession sqlSession = factory.openSession(true);
Connection connection = sqlSession.getConnection();
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
T instance = t.newInstance();
Field[] fields = t.getDeclaredFields();
for (Field field : fields) {
Method method = ClassUtil.setMethod(field.getName(), t, field.getType());
if (field.getType() == String.class) {
String v = resultSet.getString(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
boolean v = resultSet.getBoolean(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Byte.class || field.getType() == byte.class) {
byte v = resultSet.getByte(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Short.class || field.getType() == short.class) {
short v = resultSet.getShort(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Character.class || field.getType() == char.class) {
short v = resultSet.getShort(field.getName());
method.invoke(instance, (char) v);
} else if (field.getType() == Integer.class || field.getType() == int.class) {
int v = resultSet.getInt(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Long.class || field.getType() == long.class) {
long v = resultSet.getLong(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Float.class || field.getType() == float.class) {
float v = resultSet.getFloat(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Double.class || field.getType() == double.class) {
double v = resultSet.getDouble(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Byte[].class || field.getType() == byte[].class) {
byte[] v = resultSet.getBytes(field.getName());
method.invoke(instance, v);
} else if (field.getType() == Date.class) {
Date v = resultSet.getDate(field.getName());
method.invoke(instance, v);
} else {
String v = resultSet.getString(field.getName());
method.invoke(instance, v);
}
}
result.add(instance);
}
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return result;
}
}

@ -1,7 +1,51 @@
package xyz.wbsite.dbtool.web.frame.utils;
import java.util.Arrays;
public class StringUtil {
/**
*
*
* @param text
* @param length
* @param c
* @return
*/
public static String padRight(String text, int length, char c) {
if (text == null) {
throw new IllegalArgumentException("text can not be null!");
}
if (text.length() > length) {
throw new IllegalArgumentException("text's length " + text.length() + " is too long!");
}
char[] array = new char[length];
Arrays.fill(array, text.length(), length, c);
System.arraycopy(text.toCharArray(), 0, array, 0, text.length());
return new String(array);
}
/**
*
*
* @param text
* @param length
* @param c
* @return
*/
public static String padLeft(String text, int length, char c) {
if (text == null) {
throw new IllegalArgumentException("text can not be null!");
}
if (text.length() > length) {
throw new IllegalArgumentException("text's length " + text.length() + " is too long!");
}
char[] array = new char[length];
Arrays.fill(array, 0, length - text.length(), c);
System.arraycopy(text.toCharArray(), 0, array, length - text.length(), text.length());
return new String(array);
}
public static int getByteLength(String str) {
int length = str.replaceAll("[^\\x00-\\xff]", "**").length();
return length;

@ -34,8 +34,8 @@ public class UrlUtil {
// 端口
int serverPort = request.getServerPort();
// 上下文路径
String contextPath = request.getContextPath();
String context = request.getContextPath();
return String.format(Locale.CHINA, "%s://%s:%d%s%s", scheme, serverName, serverPort, contextPath, url);
return String.format(Locale.CHINA, "%s://%s:%d%s%s", scheme, serverName, serverPort, context, url);
}
}

@ -8,6 +8,8 @@ import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
@ -45,4 +47,26 @@ public class ValidationUtil {
}
return response;
}
public static List<String> validate(Object req) {
List<String> validResult = new ArrayList<>();
if (req == null) {
validResult.add("当前数据为空");
return validResult;
}
try {
Validator validator = factory.getValidator();
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(req);
if (constraintViolations.size() > 0) {
for (ConstraintViolation<Object> violation : constraintViolations) {
validResult.add(violation.getMessage());
}
}
} catch (Exception e) {
e.printStackTrace();
validResult.add("数据检查错误");
}
return validResult;
}
}

@ -10,6 +10,13 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* ZipUtil - Zip
*
* @author wangbing
* @version 0.0.1
* @since 2017-01-01
*/
public class ZipUtil {
/**
@ -132,11 +139,4 @@ public class ZipUtil {
in.close();
}
}
public static void main(String[] args) {
//解压
unZip(new File("E:\\AAA.zip"), new File("E:\\AAA"));
//压缩
toZip(new File("E:\\AAA"), new File("E:\\AAA.zip"));
}
}

@ -1,21 +0,0 @@
package xyz.wbsite.dbtool.web.frame.validation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DictValidator.class)
public @interface Dict {
String message() default "字典项错误";
String name() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

@ -1,36 +0,0 @@
package xyz.wbsite.dbtool.web.frame.validation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
public class DictValidator implements ConstraintValidator<Dict, String> {
private String name;
@Override
public void initialize(Dict constraint) {
name = constraint.name();
}
@Override
public boolean isValid(String o, ConstraintValidatorContext constraintValidatorContext) {
if (null == o) {
return true;
} else if (name == null) {
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext.buildConstraintViolationWithTemplate("字典名称为空").addConstraintViolation();
return false;
} else {
// name 字典名称
HashSet<String> codeSet = new HashSet<>();
if (codeSet.contains(o)) {
return true;
} else {
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext.buildConstraintViolationWithTemplate("非法的字典[" + name + "]值").addConstraintViolation();
return false;
}
}
}
}

@ -10,12 +10,17 @@ import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
public class FileUtil {
public static List<String> readFile2Lines(String fileName) {
public static List<String> readFileToLines(File filePath) {
return readFileToLines(filePath.getAbsoluteFile());
}
public static List<String> readFileToLines(String fileName) {
List<String> returnString = new ArrayList<String>();
File file = new File(fileName);
BufferedReader reader = null;
@ -77,6 +82,36 @@ public class FileUtil {
return var5;
}
public static boolean writeStringToFile(String data, File file, boolean isNewLine, boolean isAppend) {
PrintWriter printWriter = null;
try {
printWriter = openPrintWriter(file);
if (isNewLine && isAppend) {// 换行追加
printWriter.println();
printWriter.append(data);
} else if (!isNewLine && isAppend) {// 不换行追加
printWriter.append(data);
} else {// 直接写入
printWriter.print(data);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (printWriter != null) printWriter.close();
}
}
public static PrintWriter openPrintWriter(File file) {
try {
return new PrintWriter(new FileOutputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
public static FileInputStream openInputStream(File file) throws IOException {
if (file.exists()) {
if (file.isDirectory()) {

@ -56,7 +56,8 @@ public class ResourceUtil extends ResourceUtils {
ClassPathResource cpr = new ClassPathResource(resourcePath);
File in = cpr.getFile();
for (File file : in.listFiles()) {
result.add(file.getName());
String name = file.getName();
if (name.matches(".+\\..+")) result.add(name);
}
return result;
} catch (IOException e) {

@ -162,7 +162,7 @@
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
<version>19.3.0.0</version>
</dependency>
</#if>
</dependencies>

Loading…
Cancel
Save

Powered by TurnKey Linux.