diff --git a/admin/src/main/java/com/example/action/GlobalController.java b/admin/src/main/java/com/example/action/GlobalController.java
deleted file mode 100644
index e6496fb..0000000
--- a/admin/src/main/java/com/example/action/GlobalController.java
+++ /dev/null
@@ -1,247 +0,0 @@
-package com.example.action;
-
-import com.example.frame.base.FileUploadResponse;
-import com.example.frame.base.BaseResponse;
-import com.example.frame.base.ErrorType;
-import com.example.frame.base.Screen;
-import com.example.frame.utils.LocalData;
-import com.example.config.ActionConfig;
-import com.example.frame.utils.MapperUtil;
-import org.springframework.beans.BeansException;
-import org.apache.commons.io.FileUtils;
-import org.springframework.boot.web.servlet.error.ErrorController;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.multipart.MultipartHttpServletRequest;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-import java.io.IOException;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Consumer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * 全局请求Controller,如果无特殊请求,则不需再增加其他Controller
- * 全局htm后缀入口{@link GlobalController#hold}
- * 全局异常捕捉{@link GlobalController#excepitonHandler}
- * 全局上传接口{@link GlobalController#upload}
- * 全局下载接口{@link GlobalController#download}
- *
- * 说明Request命名规则,驼峰式命名
- * Api#Example#Request ==> 目标#动作#Request
- *
- * @author author
- * @version 0.0.1
- * @since 2019-06-16
- */
-@Controller
-@ControllerAdvice
-public class GlobalController implements ErrorController {
-
- @Value("${web.welcome.page}")
- private String homePage;
-
- /**
- * 全局异常捕捉
- *
- * @param request
- * @param response
- * @param exception 要捕获的异常
- * @return
- */
- @ExceptionHandler(Exception.class)
- public String excepitonHandler(HttpServletRequest request, HttpServletResponse response, Model model, Exception exception) {
- StringBuffer msg = new StringBuffer("");
- if (exception != null) {
- msg = new StringBuffer("");
- String message = exception.toString();
- int length = exception.getStackTrace().length;
- if (length > 0) {
- msg.append("").append(message).append("
");
- for (int i = 0; i < length; i++) {
- msg.append("").append(exception.getStackTrace()[i]).append("
");
- }
- } else {
- msg.append(message);
- }
- }
- response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- model.addAttribute("msg", msg.toString());
- return "500";
- }
-
- private final static String ERROR_PATH = "/error";
-
- @Override
- public String getErrorPath() {
- return ERROR_PATH;
- }
-
- @RequestMapping(value = ERROR_PATH)
- public String error(HttpServletRequest request) {
- Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
-
- switch (statusCode) {
- case 404:
- return "404";
- case 403:
- try {
- LocalData.getResponse().sendRedirect("/login.htm");
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "403";
- case 500:
- return "500";
- default:
- return "403";
- }
- }
-
- @RequestMapping("/")
- public String home() {
- return "forward:" + homePage;
- }
-
- /**
- * 当未明确指定控制器时,走该请求,默认返回对应的layout布局和screen视图
- * 当需要使用layout时,不需要返回值,ViewNameTranslator会处理对应关系
- *
- * @param model
- * @param request
- */
- @RequestMapping({"/**/*.htm"})
- public void hold(HttpServletRequest request, Model model) {
- HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
-
- // 尝试执行Target Screen执行器(服务器渲染),不存在则直接返回视图模板(Ajax渲染)
- Screen screenExec = null;
- try {
- String target = LocalData.getTarget();
- target = target.replaceAll("/", ".").toLowerCase();
- screenExec = LocalData.getApplicationContext().getBean(ActionConfig.SCREEN_PREFIX + target, Screen.class);
- screenExec.exec(model, request, response);
- } catch (BeansException e) {
-
- }
-
- //todo 可在此获取共性数据(也可以在全局拦截器GlobalHandlerInterceptor、拦截器作用域比此更高),
- //todo 例如用户信息等。其他业务数据在页面渲染后通过Ajax请求
- }
-
- @RequestMapping("/upload")
- @ResponseBody
- public BaseResponse upload(HttpServletRequest request) {
- FileUploadResponse fileUploadResponse = new FileUploadResponse();
- MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
- MultipartFile target = multipartHttpServletRequest.getFile("file");
-
- String fileName = target.getOriginalFilename();
-
- //========
- //处理文件
- //========
- fileUploadResponse.setId(1L);
- fileUploadResponse.setUrl("example.com\\img\\1.jpg");
- fileUploadResponse.setDownloadUrl("example.com\\img\\1.jpg");
-
-
- if (target != null) {
- fileUploadResponse.addError(ErrorType.BUSINESS_ERROR, "文件上传成功,但未处理文件[" + fileName + "]!");
- } else {
- fileUploadResponse.addError(ErrorType.BUSINESS_ERROR, "文件上传失败!");
- }
-
- return fileUploadResponse;
- }
-
- @RequestMapping("/download")
- @ResponseBody
- public ResponseEntity download(@RequestParam(value = "file", required = false) String file) throws IOException {
-
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
-
- //========
- //下载DEMO
- //========
- if (file == null) {
- file = "test.txt";
- headers.setContentDispositionFormData("attachment", new String(file.getBytes("UTF-8"), "iso-8859-1"));
- return new ResponseEntity("test".getBytes(),
- headers, HttpStatus.CREATED);
- }
-
- return new ResponseEntity(FileUtils.readFileToByteArray(new File(file)),
- headers, HttpStatus.CREATED);
- }
-
- private static ConcurrentHashMap sseMap = new ConcurrentHashMap();
-
- /**
- * Sse推送服务,服务器向js推送自定义消息
- * Sse容器{@link GlobalController#sseMap}
- * Sse批量推送{@link GlobalController#pushAll}
- */
- @RequestMapping(value = "/sse/{userId}", produces = "text/event-stream;charset=UTF-8")
- public SseEmitter sse(@PathVariable String userId) {
- SseEmitter sseEmitter = new SseEmitter(10000000L);
- sseEmitter.onError(new Consumer() {
- private String key = userId;
-
- @Override
- public void accept(Throwable throwable) {
- sseMap.remove(key);
- }
- });
- sseEmitter.onCompletion(new Runnable() {
- private String key = userId;
-
- @Override
- public void run() {
- sseMap.remove(key);
- }
- });
- if (sseMap.get(userId) != null) {
- sseMap.remove(userId);
- }
- sseMap.put(userId, sseEmitter);
-
- return sseEmitter;
- }
-
- /**
- * Sse批量推送
- *
- * @param data 推送对象
- */
- public void pushAll(Object data) {
- for (String s : sseMap.keySet()) {
- try {
- sseMap.get(s).send(MapperUtil.toJson(data), MediaType.APPLICATION_JSON);
- } catch (IOException e) {
- sseMap.remove(s);
- }
- }
- }
-}
diff --git a/admin/src/main/java/com/example/config/ActionConfig.java b/admin/src/main/java/com/example/config/ActionConfig.java
deleted file mode 100644
index e087d8d..0000000
--- a/admin/src/main/java/com/example/config/ActionConfig.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.example.config;
-
-import com.example.frame.base.Control;
-import com.example.frame.base.Screen;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
-import org.springframework.beans.factory.support.BeanNameGenerator;
-import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.type.classreading.MetadataReader;
-import org.springframework.core.type.classreading.MetadataReaderFactory;
-import org.springframework.core.type.filter.TypeFilter;
-
-import java.io.IOException;
-
-/**
- * 请求处理器配置类,Screen及Control
- *
- * 注册扫描Screen处理器 {@link ActionConfig#registryScreen}
- * 注册扫描Control处理器 {@link ActionConfig#registryControl}
- *
- * @author wangbing
- * @version 0.0.1
- * @since 2017-01-01
- */
-@Configuration
-public class ActionConfig implements BeanDefinitionRegistryPostProcessor {
- public static final String SCREEN_PREFIX = "screen";
- public static final String CONTROL_PREFIX = "control";
-
- @Override
- public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
- String aPackage = this.getClass().getPackage().getName();
- int i = registryScreen("com.example.action.screen", beanDefinitionRegistry);
- int i1 = registryControl("com.example.action.control", beanDefinitionRegistry);
- System.out.println();
- }
-
- @Override
- public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
-
- }
-
- private int registryScreen(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
- ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
- classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
- @Override
- public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
- if (metadataReader.getClassMetadata().getSuperClassName().equals(Screen.class.getName())) {
- return true;
- }
- return false;
- }
- });
- classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
- @Override
- public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
- String beanClassName = beanDefinition.getBeanClassName();
- String s = beanClassName.replaceAll(basePackage, SCREEN_PREFIX);
- return s.toLowerCase();
- }
- });
- return classPathBeanDefinitionScanner.scan(basePackage);
- }
-
- private int registryControl(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
- ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
- classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
- @Override
- public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
- if (metadataReader.getClassMetadata().getSuperClassName().equals(Control.class.getName())) {
- return true;
- }
- return false;
- }
- });
- classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
- @Override
- public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
- String beanClassName = beanDefinition.getBeanClassName();
- String s = beanClassName.replaceAll(basePackage, CONTROL_PREFIX);
- return s.toLowerCase();
- }
- });
- return classPathBeanDefinitionScanner.scan(basePackage);
- }
-}
diff --git a/admin/src/main/java/com/example/module/admin/rsp/LoginResponse.java b/admin/src/main/java/com/example/module/admin/rsp/LoginResponse.java
deleted file mode 100644
index fe40dae..0000000
--- a/admin/src/main/java/com/example/module/admin/rsp/LoginResponse.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.example.module.admin.rsp;
-
-import com.example.frame.base.BaseResponse;
-
-
-public class LoginResponse extends BaseResponse {
-
-
-}
diff --git a/admin/src/main/java/com/example/Application.java b/admin/src/main/java/xyz/wbsite/Application.java
similarity index 97%
rename from admin/src/main/java/com/example/Application.java
rename to admin/src/main/java/xyz/wbsite/Application.java
index a223156..28fa3d4 100644
--- a/admin/src/main/java/com/example/Application.java
+++ b/admin/src/main/java/xyz/wbsite/Application.java
@@ -1,4 +1,4 @@
-package com.example;
+package xyz.wbsite;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
diff --git a/admin/src/main/java/com/example/action/AjaxController.java b/admin/src/main/java/xyz/wbsite/action/AjaxController.java
similarity index 90%
rename from admin/src/main/java/com/example/action/AjaxController.java
rename to admin/src/main/java/xyz/wbsite/action/AjaxController.java
index b5abcba..1252f2f 100644
--- a/admin/src/main/java/com/example/action/AjaxController.java
+++ b/admin/src/main/java/xyz/wbsite/action/AjaxController.java
@@ -1,26 +1,26 @@
-package com.example.action;
+package xyz.wbsite.action;
-import com.example.frame.base.BaseResponse;
-import com.example.frame.base.Error;
-import com.example.frame.base.ErrorType;
-import com.example.frame.base.Token;
-import com.example.frame.utils.LocalData;
-import com.example.frame.utils.LogUtil;
-import com.example.frame.utils.MD5Util;
-import com.example.frame.utils.MapperUtil;
-import com.example.frame.utils.Message;
-import com.example.frame.utils.ProcessUtil;
-import com.example.frame.utils.ValidationUtil;
-import com.example.module.admin.ent.Mapping;
-import com.example.module.admin.ent.NginxCtrl;
-import com.example.module.admin.mgr.MappingManager;
-import com.example.module.admin.req.LoginRequest;
-import com.example.module.admin.req.MappingCreateRequest;
-import com.example.module.admin.req.MappingDeleteRequest;
-import com.example.module.admin.req.MappingFindRequest;
-import com.example.module.admin.req.MappingUpdateRequest;
-import com.example.module.admin.rsp.LoginResponse;
-import com.example.module.admin.rsp.MappingFindResponse;
+import xyz.wbsite.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.Error;
+import xyz.wbsite.frame.base.ErrorType;
+import xyz.wbsite.frame.base.Token;
+import xyz.wbsite.frame.utils.LocalData;
+import xyz.wbsite.frame.utils.LogUtil;
+import xyz.wbsite.frame.utils.MD5Util;
+import xyz.wbsite.frame.utils.MapperUtil;
+import xyz.wbsite.frame.utils.Message;
+import xyz.wbsite.frame.utils.ProcessUtil;
+import xyz.wbsite.frame.utils.ValidationUtil;
+import xyz.wbsite.module.admin.ent.Mapping;
+import xyz.wbsite.module.admin.ent.NginxCtrl;
+import xyz.wbsite.module.admin.mgr.MappingManager;
+import xyz.wbsite.module.admin.req.LoginRequest;
+import xyz.wbsite.module.admin.req.MappingCreateRequest;
+import xyz.wbsite.module.admin.req.MappingDeleteRequest;
+import xyz.wbsite.module.admin.req.MappingFindRequest;
+import xyz.wbsite.module.admin.req.MappingUpdateRequest;
+import xyz.wbsite.module.admin.rsp.LoginResponse;
+import xyz.wbsite.module.admin.rsp.MappingFindResponse;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/admin/src/main/java/xyz/wbsite/action/GlobalController.java b/admin/src/main/java/xyz/wbsite/action/GlobalController.java
new file mode 100644
index 0000000..c046bce
--- /dev/null
+++ b/admin/src/main/java/xyz/wbsite/action/GlobalController.java
@@ -0,0 +1,454 @@
+package xyz.wbsite.action;
+
+import com.fasterxml.jackson.core.TreeNode;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.error.ErrorController;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
+import xyz.wbsite.config.ActionConfig;
+import xyz.wbsite.frame.base.BaseRequest;
+import xyz.wbsite.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.ErrorType;
+import xyz.wbsite.frame.base.Screen;
+import xyz.wbsite.frame.base.Token;
+import xyz.wbsite.frame.utils.AESUtil;
+import xyz.wbsite.frame.utils.LocalData;
+import xyz.wbsite.frame.utils.LogUtil;
+import xyz.wbsite.frame.utils.MD5Util;
+import xyz.wbsite.frame.utils.MapperUtil;
+import xyz.wbsite.frame.utils.RequestUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Locale;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 全局请求Controller,如果无特殊请求,则不需再增加其他Controller
+ * 全局htm后缀入口{@link GlobalController#action(Model, HttpServletRequest, HttpServletResponse)}
+ * 全局ajax入口{@link GlobalController#ajax(String, String, String, HttpServletRequest, HttpServletResponse, String, MultipartFile)}
+ * 全局异常捕捉{@link GlobalController#exceptionHandler(HttpServletRequest, HttpServletResponse, Model, Exception)}
+ * 全局消息订阅{@link GlobalController#sse(String)}
+ *
+ * 说明Request命名规则,驼峰式命名
+ * Api#Example#Request ==> 目标#动作#Request
+ *
+ * @author author
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Controller
+@ControllerAdvice
+public class GlobalController implements ErrorController {
+
+ @Value("${r'${server.servlet.context-path}'}")
+ private String context;
+ @Value("${r'${web.home.page}'}")
+ private String homePage;
+ @Value("${r'${web.login.page}'}")
+ private String loginPage;
+ @Autowired
+ private FreeMarkerViewResolver viewResolver;
+
+ /**
+ * 全局异常捕捉
+ *
+ * @param request
+ * @param response
+ * @param exception 要捕获的异常
+ * @return
+ */
+ @ExceptionHandler(Exception.class)
+ public String exceptionHandler(HttpServletRequest request, HttpServletResponse response, Model model, Exception exception) {
+ StringBuffer msg = new StringBuffer("");
+ if (exception != null) {
+ msg = new StringBuffer("");
+ String message = exception.toString();
+ int length = exception.getStackTrace().length;
+ if (length > 0) {
+ msg.append("").append(message).append("
");
+ for (int i = 0; i < length; i++) {
+ msg.append("").append(exception.getStackTrace()[i]).append("
");
+ }
+ } else {
+ msg.append(message);
+ }
+ }
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ model.addAttribute("msg", msg.toString());
+ return "500";
+ }
+
+ private final static String ERROR_PATH = "/error";
+
+ @Override
+ public String getErrorPath() {
+ return ERROR_PATH;
+ }
+
+ @RequestMapping(value = ERROR_PATH)
+ public String error(HttpServletRequest request, HttpServletResponse response) {
+ switch (response.getStatus()) {
+ case 404:
+ return "404";
+ case 403:
+ String errorUrl = RequestUtil.getErrorUrl(request);
+ errorUrl = errorUrl.replaceFirst(context, "");
+ if ((errorUrl.equals(homePage) || errorUrl.equals("/")) && LocalData.getToken() == null) {
+ try {
+ response.sendRedirect(context + loginPage);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return "403";
+ case 500:
+ return "500";
+ default:
+ return "403";
+ }
+ }
+
+ @RequestMapping("/")
+ public String home() {
+ Token token = LocalData.getToken();
+ if (token == null) {
+ return "redirect:" + loginPage;
+ } else {
+ return "redirect:" + homePage;
+ }
+ }
+
+ /**
+ * 当未明确指定控制器时,走该请求,默认返回对应的layout布局和screen视图
+ * 当需要使用layout时,不需要返回值,ViewNameTranslator会处理对应关系
+ *
+ * @param model
+ * @param request
+ */
+ @RequestMapping({"/**/*.htm"})
+ public String action(Model model, HttpServletRequest request, HttpServletResponse response) {
+ String servletPath = request.getServletPath();// /**/*.htm
+ String layout = "/layout/default";
+ String action = LocalData.getAction();// **/*
+
+ Pattern compile = Pattern.compile("^/(.+)\\.htm");
+ Matcher matcher = compile.matcher(servletPath);
+ if (matcher.find()) {
+ action = matcher.group(1);
+ LocalData.setAction(action);
+ }
+
+ try {
+ LocaleResolver localeResolver = (LocaleResolver) request.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE);
+ Locale locale = localeResolver.resolveLocale(request);
+
+ {//查询screen
+ String[] split = action.split("/");
+ StringBuilder sb = new StringBuilder("");
+ sb.append("screen");
+ for (int i = 0; i < split.length; i++) {
+ sb.append(File.separator);
+ sb.append(split[i]);
+ }
+ layout = sb.toString();
+ View view = viewResolver.resolveViewName(layout, locale);
+ if (view == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "");
+ return null;
+ }
+
+ // 尝试执行Screen执行器(服务器渲染),并返回视图模板
+ try {
+ String beanClassName = (ActionConfig.SCREEN_PREFIX + action).toLowerCase();
+ Screen screenExec = LocalData.getApplicationContext().getBean(beanClassName, Screen.class);
+ screenExec.exec(model, request, response);
+
+ if (response.getStatus() != HttpServletResponse.SC_OK) {
+ response.sendError(response.getStatus(), "");
+ return null;
+ }
+ } catch (BeansException e) {
+
+ }
+ }
+
+ {//查找layout
+ String[] split = action.split("/");
+
+ int lt = split.length;
+ while (lt > 0) {
+
+ StringBuilder sb = new StringBuilder("");
+ sb.append("layout");
+ for (int i = 0; i < lt - 1; i++) {
+ sb.append(File.separator);
+ sb.append(split[i]);
+ }
+
+ layout = sb.toString() + File.separator + split[split.length - 1];
+
+ View view = viewResolver.resolveViewName(layout, locale);
+ //无法找到对应layout,使用默认layout
+ if (view == null) {
+ layout = sb.toString() + File.separator + "default";
+ View defaultView = viewResolver.resolveViewName(layout, locale);
+ if (null == defaultView && lt == 1) {
+ System.err.println("can not find layout/default.ftl");
+ } else if (null == defaultView) {
+ lt--;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ } catch (Exception e) {
+ return exceptionHandler(request, response, model, e);
+ }
+
+ // todo 可在此获取共性数据(也可以在全局拦截器GlobalHandlerInterceptor、拦截器作用域比此更高),
+ // todo 例如用户信息等。其他业务数据在页面渲染后通过Ajax请求
+ return layout;
+ }
+
+ @RequestMapping("/ajax/{module}/{target}/{method}")
+ @ResponseBody
+ public Object ajax(
+ @PathVariable String module,
+ @PathVariable String target,
+ @PathVariable String method,
+ HttpServletRequest httpServletRequest,
+ HttpServletResponse httpServletResponse,
+ @RequestBody(required = false) String data,
+ @RequestParam(name = "file", required = false) MultipartFile file) {
+ try {
+ String beanClassName = (ActionConfig.AJAX_PREFIX + module + "/" + target).toLowerCase();
+ Object ajax = LocalData.getApplicationContext().getBean(beanClassName);
+
+ Class ajaxClass = ajax.getClass();
+
+ Method[] methods = ajaxClass.getDeclaredMethods();
+
+ Method methodC = null;
+ for (Method meth : methods) {
+ if (meth.getName().equals(method)) {
+ methodC = meth;
+ }
+ }
+
+ if (methodC == null) {
+ BaseResponse baseResponse = new BaseResponse();
+ baseResponse.addError(ErrorType.BUSINESS_ERROR, "未找到对应的方法!");
+ return baseResponse;
+ }
+
+ Parameter[] parameters = methodC.getParameters();
+ Object[] arg = new Object[parameters.length];
+
+ for (int i = 0; i < parameters.length; i++) {
+ Parameter parameter = parameters[i];
+ if (parameter.getType() == HttpServletRequest.class) {
+ arg[i] = httpServletRequest;
+ } else if (parameter.getType() == HttpServletResponse.class) {
+ arg[i] = httpServletResponse;
+ } else if (parameter.getType() == TreeNode.class) {
+ arg[i] = MapperUtil.toTree(data);
+ } else if (parameter.getType() == String.class) {
+ arg[i] = data;
+ } else if (parameter.getType() == MultipartFile.class) {
+ arg[i] = file;
+ } else if (BaseRequest.class.isAssignableFrom(parameter.getType())) {
+ arg[i] = MapperUtil.toJava(data, parameter.getType());
+ } else if (parameter.getType() == Token.class) {
+ arg[i] = LocalData.getToken();
+ } else {
+ arg[i] = null;
+ }
+ }
+ return methodC.invoke(ajax, arg);
+ } catch (BeansException e) {
+ e.printStackTrace();
+ BaseResponse baseResponse = new BaseResponse();
+ baseResponse.addError(ErrorType.BUSINESS_ERROR, "未找到对应的目标!");
+ return baseResponse;
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ BaseResponse baseResponse = new BaseResponse();
+ baseResponse.addError(ErrorType.BUSINESS_ERROR, "方法执必须公开!");
+ return baseResponse;
+ } catch (InvocationTargetException e) {
+ e.getTargetException().printStackTrace();
+ BaseResponse baseResponse = new BaseResponse();
+ baseResponse.addError(ErrorType.BUSINESS_ERROR, "方法执行错误[" + e.getTargetException().getMessage() + "]");
+ return baseResponse;
+ }
+ }
+
+
+ @RequestMapping(path = "/api/{module}/{target}/{method}", method = RequestMethod.POST)
+ @ResponseBody
+ public String api(
+ @PathVariable String module,
+ @PathVariable String target,
+ @PathVariable String method,
+ @RequestParam(required = false) String appKey,
+ @RequestParam(required = false) String sign,
+ @RequestParam(required = false) Long timestamp,
+ @RequestParam(required = false) String token,
+ @RequestParam(required = false) String encryptData,
+ HttpServletRequest httpServletRequest,
+ HttpServletResponse httpServletResponse) {
+ BaseResponse response = new BaseResponse();
+ if (appKey == null) {
+ response.addError(ErrorType.BUSINESS_ERROR, "应用码参数[appKey]不存在!");
+ return MapperUtil.toJson(response);
+ } else if (sign == null) {
+ response.addError(ErrorType.BUSINESS_ERROR, "签名参数[sign]不存在!");
+ return MapperUtil.toJson(response);
+ } else if (timestamp == null) {
+ response.addError(ErrorType.BUSINESS_ERROR, "时间戳参数[timestamp]不存在!");
+ return MapperUtil.toJson(response);
+ }
+
+ String data = null;
+ String appSecret = "1234567890123456";
+ // 解码
+ try {
+ data = AESUtil.decrypt2String(encryptData, appSecret);
+ } catch (Exception e) {
+ response.addError(ErrorType.BUSINESS_ERROR, "解码失败,请确认编码是否正确!");
+ return MapperUtil.toJson(response);
+ }
+
+ // 验证签名
+ String sign_ = MD5Util.encode(appSecret + data + timestamp);
+ if (!sign_.equals(sign)) {
+ response.addError(ErrorType.BUSINESS_ERROR, "签名验证失败!");
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ // 时效性验证
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - timestamp > 2 * 60 * 1000) {
+ response.addError(ErrorType.BUSINESS_ERROR, "请求过期, 或本地时间错误!");
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ // 权限验证
+ if (!LocalData.getToken().hasRes(httpServletRequest.getServletPath())) {
+ response.addError(ErrorType.BUSINESS_ERROR, "[" + httpServletRequest.getServletPath() + "]未授权的资源!");
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ // 开始处理业务
+ try {
+ String beanClassName = (ActionConfig.API_PREFIX + module + "/" + target).toLowerCase();
+ Object ajax = LocalData.getApplicationContext().getBean(beanClassName);
+ Class ajaxClass = ajax.getClass();
+ Method[] methods = ajaxClass.getDeclaredMethods();
+
+ Method methodC = null;
+ for (Method meth : methods) {
+ if (meth.getName().equals(method)) {
+ methodC = meth;
+ }
+ }
+
+ if (methodC == null) {
+ response.addError(ErrorType.BUSINESS_ERROR, "未找到对应的方法!");
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ Parameter[] parameters = methodC.getParameters();
+ Object[] arg = new Object[parameters.length];
+
+ for (int i = 0; i < parameters.length; i++) {
+ Parameter parameter = parameters[i];
+ if (parameter.getType() == HttpServletRequest.class) {
+ arg[i] = httpServletRequest;
+ } else if (parameter.getType() == HttpServletResponse.class) {
+ arg[i] = httpServletResponse;
+ } else if (BaseRequest.class.isAssignableFrom(parameter.getType())) {
+ arg[i] = MapperUtil.toJava(data, parameter.getType());
+ } else if (parameter.getType() == TreeNode.class) {
+ arg[i] = MapperUtil.toTree(data);
+ } else if (parameter.getType() == Token.class) {
+ arg[i] = LocalData.getToken();
+ } else {
+ arg[i] = null;
+ }
+ }
+ response = (BaseResponse) methodC.invoke(ajax, arg);
+ } catch (BeansException e) {
+ e.printStackTrace();
+ response.addError(ErrorType.BUSINESS_ERROR, "未找到对应的目标!");
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ response.addError(ErrorType.BUSINESS_ERROR, "方法执必须公开!");
+ } catch (InvocationTargetException e) {
+ LogUtil.dumpException(e.getTargetException());
+ e.getTargetException().printStackTrace();
+ response.addError(ErrorType.BUSINESS_ERROR, "方法执行错误[" + e.getTargetException().getMessage() + "]");
+ }
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ private static ConcurrentHashMap sseMap = new ConcurrentHashMap();
+
+ /**
+ * Sse推送服务,服务器向js推送自定义消息
+ * Sse容器{@link GlobalController#sseMap}
+ * Sse批量推送{@link GlobalController#pushAll}
+ */
+ @RequestMapping(value = "/sse/{userId}", produces = "text/event-stream;charset=UTF-8")
+ public SseEmitter sse(@PathVariable String userId) {
+ SseEmitter sseEmitter = new SseEmitter(10000000L);
+ if (sseMap.get(userId) != null) {
+ sseMap.remove(userId);
+ }
+ sseMap.put(userId, sseEmitter);
+ return sseEmitter;
+ }
+
+ /**
+ * Sse批量推送
+ *
+ * @param data 推送对象
+ */
+ public static void pushAll(Object data) {
+ for (String s : sseMap.keySet()) {
+ try {
+ sseMap.get(s).send(MapperUtil.toJson(data), MediaType.APPLICATION_JSON);
+ } catch (IOException e) {
+ sseMap.remove(s);
+ }
+ }
+ }
+}
diff --git a/admin/src/main/java/xyz/wbsite/action/ajax/MappingAjax.java b/admin/src/main/java/xyz/wbsite/action/ajax/MappingAjax.java
new file mode 100644
index 0000000..fe52e63
--- /dev/null
+++ b/admin/src/main/java/xyz/wbsite/action/ajax/MappingAjax.java
@@ -0,0 +1,21 @@
+package xyz.wbsite.action.ajax;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.multipart.MultipartFile;
+import xyz.wbsite.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.ErrorType;
+import xyz.wbsite.frame.utils.LogUtil;
+import xyz.wbsite.frame.utils.MapperUtil;
+import xyz.wbsite.frame.utils.ValidationUtil;
+import xyz.wbsite.module.admin.mgr.MappingManager;
+
+import java.io.IOException;
+import java.util.List;
+
+public class MappingAjax {
+
+ @Autowired
+ private MappingManager mappingManager;
+
+
+}
diff --git a/admin/src/main/java/com/example/action/control/Footer.java b/admin/src/main/java/xyz/wbsite/action/control/Footer.java
similarity index 79%
rename from admin/src/main/java/com/example/action/control/Footer.java
rename to admin/src/main/java/xyz/wbsite/action/control/Footer.java
index a53ce95..adaaf85 100644
--- a/admin/src/main/java/com/example/action/control/Footer.java
+++ b/admin/src/main/java/xyz/wbsite/action/control/Footer.java
@@ -1,6 +1,6 @@
-package com.example.action.control;
+package xyz.wbsite.action.control;
-import com.example.frame.base.Control;
+import xyz.wbsite.frame.base.Control;
import org.springframework.ui.Model;
import javax.servlet.http.HttpServletRequest;
diff --git a/admin/src/main/java/com/example/action/control/Header.java b/admin/src/main/java/xyz/wbsite/action/control/Header.java
similarity index 79%
rename from admin/src/main/java/com/example/action/control/Header.java
rename to admin/src/main/java/xyz/wbsite/action/control/Header.java
index 32e8be5..c365fb7 100644
--- a/admin/src/main/java/com/example/action/control/Header.java
+++ b/admin/src/main/java/xyz/wbsite/action/control/Header.java
@@ -1,6 +1,6 @@
-package com.example.action.control;
+package xyz.wbsite.action.control;
-import com.example.frame.base.Control;
+import xyz.wbsite.frame.base.Control;
import org.springframework.ui.Model;
import javax.servlet.http.HttpServletRequest;
diff --git a/admin/src/main/java/com/example/action/screen/Index.java b/admin/src/main/java/xyz/wbsite/action/screen/Index.java
similarity index 89%
rename from admin/src/main/java/com/example/action/screen/Index.java
rename to admin/src/main/java/xyz/wbsite/action/screen/Index.java
index b06dd67..30211fa 100644
--- a/admin/src/main/java/com/example/action/screen/Index.java
+++ b/admin/src/main/java/xyz/wbsite/action/screen/Index.java
@@ -1,6 +1,6 @@
-package com.example.action.screen;
+package xyz.wbsite.action.screen;
-import com.example.frame.base.Screen;
+import xyz.wbsite.frame.base.Screen;
import org.springframework.ui.Model;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
diff --git a/admin/src/main/java/com/example/action/screen/Mapping.java b/admin/src/main/java/xyz/wbsite/action/screen/Mapping.java
similarity index 84%
rename from admin/src/main/java/com/example/action/screen/Mapping.java
rename to admin/src/main/java/xyz/wbsite/action/screen/Mapping.java
index cf63946..19d2957 100644
--- a/admin/src/main/java/com/example/action/screen/Mapping.java
+++ b/admin/src/main/java/xyz/wbsite/action/screen/Mapping.java
@@ -1,7 +1,7 @@
-package com.example.action.screen;
+package xyz.wbsite.action.screen;
-import com.example.frame.base.Screen;
-import com.example.module.admin.ent.NginxCtrl;
+import xyz.wbsite.frame.base.Screen;
+import xyz.wbsite.module.admin.ent.NginxCtrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.Model;
diff --git a/admin/src/main/java/xyz/wbsite/config/ActionConfig.java b/admin/src/main/java/xyz/wbsite/config/ActionConfig.java
new file mode 100644
index 0000000..ad8f7a6
--- /dev/null
+++ b/admin/src/main/java/xyz/wbsite/config/ActionConfig.java
@@ -0,0 +1,139 @@
+package xyz.wbsite.config;
+
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
+import org.springframework.beans.factory.support.BeanNameGenerator;
+import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.core.type.filter.AssignableTypeFilter;
+import org.springframework.core.type.filter.TypeFilter;
+import xyz.wbsite.frame.base.Control;
+import xyz.wbsite.frame.base.Screen;
+import xyz.wbsite.frame.utils.LogUtil;
+
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 请求处理器配置类,Screen及Control
+ *
+ * 注册扫描Screen处理器 {@link ActionConfig#registryScreen}
+ * 注册扫描Control处理器 {@link ActionConfig#registryControl}
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Configuration
+public class ActionConfig implements BeanDefinitionRegistryPostProcessor {
+
+ public static String SCREEN_PREFIX = "/screen/";
+ public static String CONTROL_PREFIX = "/control/";
+ public static String AJAX_PREFIX = "/ajax/";
+ public static String API_PREFIX = "/api/";
+
+ @Override
+ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
+ String aPackage = this.getClass().getPackage().getName();
+ Pattern compile = Pattern.compile("(.*)\\.config");
+ Matcher matcher = compile.matcher(aPackage);
+ if (matcher.find()) {
+ String basePackage = matcher.group(1);
+ registryScreen(basePackage + ".action.screen", beanDefinitionRegistry);
+ registryControl(basePackage + ".action.control", beanDefinitionRegistry);
+ registryAjax(basePackage + ".action.ajax", beanDefinitionRegistry);
+ registryApi(basePackage + ".action.api", beanDefinitionRegistry);
+ }
+ }
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
+
+ }
+
+ private int registryScreen(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.resetFilters(false);
+ classPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(Screen.class));
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ String beamName = beanClassName.replaceAll(basePackage + ".", SCREEN_PREFIX).replaceAll("\\.","/").toLowerCase();
+ LogUtil.i("registry screen " + beamName);
+ return beamName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+
+ private int registryControl(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.resetFilters(false);
+ classPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(Control.class));
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ String beamName = beanClassName.replaceAll(basePackage + ".", CONTROL_PREFIX).replaceAll("\\.","/").toLowerCase();
+ LogUtil.i("registry control " + beamName);
+ return beamName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+
+ private int registryAjax(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.resetFilters(false);
+ classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
+ @Override
+ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
+ return true;
+ }
+ });
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ if (beanClassName != null && beanClassName.endsWith("Ajax")) {
+ beanClassName = beanClassName.substring(0, beanClassName.length() - 4);
+ }
+ String beamName = beanClassName.replaceAll(basePackage + ".", AJAX_PREFIX).replaceAll("\\.","/").toLowerCase();
+ LogUtil.i("registry ajax " + beamName);
+ return beamName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+
+ private int registryApi(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
+ @Override
+ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
+ return true;
+ }
+ });
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ if (beanClassName != null && beanClassName.endsWith("Api")) {
+ beanClassName = beanClassName.substring(0, beanClassName.length() - 3);
+ }
+ String beamName = beanClassName.replaceAll(basePackage + ".", API_PREFIX).replaceAll("\\.","/").toLowerCase();
+ LogUtil.i("registry api " + beamName);
+ return beamName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+}
diff --git a/admin/src/main/java/com/example/config/NginxConfig.java b/admin/src/main/java/xyz/wbsite/config/NginxConfig.java
similarity index 89%
rename from admin/src/main/java/com/example/config/NginxConfig.java
rename to admin/src/main/java/xyz/wbsite/config/NginxConfig.java
index a367194..65eeb05 100644
--- a/admin/src/main/java/com/example/config/NginxConfig.java
+++ b/admin/src/main/java/xyz/wbsite/config/NginxConfig.java
@@ -1,9 +1,8 @@
-package com.example.config;
+package xyz.wbsite.config;
-import com.example.frame.utils.FileUtil;
-import com.example.frame.utils.ZipUtil;
-import com.example.module.admin.ent.Mapping;
-import com.example.module.admin.ent.NginxCtrl;
+import xyz.wbsite.frame.utils.FileUtil;
+import xyz.wbsite.frame.utils.ZipUtil;
+import xyz.wbsite.module.admin.ent.NginxCtrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.context.annotation.Bean;
@@ -13,12 +12,9 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;
import xyz.wbsite.wsqlite.ObjectClient;
-import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.sql.SQLException;
-import java.util.ArrayList;
@Configuration
diff --git a/admin/src/main/java/com/example/config/SecurityConfig.java b/admin/src/main/java/xyz/wbsite/config/SecurityConfig.java
similarity index 94%
rename from admin/src/main/java/com/example/config/SecurityConfig.java
rename to admin/src/main/java/xyz/wbsite/config/SecurityConfig.java
index da51b8e..b9d949b 100644
--- a/admin/src/main/java/com/example/config/SecurityConfig.java
+++ b/admin/src/main/java/xyz/wbsite/config/SecurityConfig.java
@@ -1,6 +1,6 @@
-package com.example.config;
+package xyz.wbsite.config;
-import com.example.frame.utils.MD5Util;
+import xyz.wbsite.frame.utils.MD5Util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -10,13 +10,11 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
-import com.example.frame.base.Token;
-import com.example.frame.utils.CookieUtil;
-import com.example.frame.utils.LocalData;
+import xyz.wbsite.frame.base.Token;
+import xyz.wbsite.frame.utils.CookieUtil;
+import xyz.wbsite.frame.utils.LocalData;
-import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
diff --git a/admin/src/main/java/com/example/config/SqliteConfig.java b/admin/src/main/java/xyz/wbsite/config/SqliteConfig.java
similarity index 87%
rename from admin/src/main/java/com/example/config/SqliteConfig.java
rename to admin/src/main/java/xyz/wbsite/config/SqliteConfig.java
index cc56b16..7a9d558 100644
--- a/admin/src/main/java/com/example/config/SqliteConfig.java
+++ b/admin/src/main/java/xyz/wbsite/config/SqliteConfig.java
@@ -1,7 +1,6 @@
-package com.example.config;
+package xyz.wbsite.config;
-import com.example.frame.utils.IDgenerator;
-import com.example.module.admin.ent.Mapping;
+import xyz.wbsite.module.admin.ent.Mapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.context.annotation.Bean;
@@ -9,13 +8,10 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import xyz.wbsite.wsqlite.ObjectClient;
-import xyz.wbsite.wsqlite.Where;
-import javax.annotation.PostConstruct;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
-import java.util.List;
@Configuration
diff --git a/admin/src/main/java/com/example/config/TaskConfig.java b/admin/src/main/java/xyz/wbsite/config/TaskConfig.java
similarity index 80%
rename from admin/src/main/java/com/example/config/TaskConfig.java
rename to admin/src/main/java/xyz/wbsite/config/TaskConfig.java
index c9f10df..2e4c5b4 100644
--- a/admin/src/main/java/com/example/config/TaskConfig.java
+++ b/admin/src/main/java/xyz/wbsite/config/TaskConfig.java
@@ -1,15 +1,12 @@
-package com.example.config;
+package xyz.wbsite.config;
-import com.example.action.GlobalController;
-import com.example.frame.base.Message;
-import com.example.frame.base.MessageType;
-import com.example.frame.utils.LogUtil;
-import com.example.frame.utils.ProcessUtil;
-import com.example.module.admin.ent.NginxCtrl;
-import com.example.module.admin.ent.State;
+import xyz.wbsite.action.GlobalController;
+import xyz.wbsite.frame.base.Message;
+import xyz.wbsite.frame.base.MessageType;
+import xyz.wbsite.module.admin.ent.NginxCtrl;
+import xyz.wbsite.module.admin.ent.State;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
diff --git a/admin/src/main/java/com/example/config/ThreadPoolConfig.java b/admin/src/main/java/xyz/wbsite/config/ThreadPoolConfig.java
similarity index 98%
rename from admin/src/main/java/com/example/config/ThreadPoolConfig.java
rename to admin/src/main/java/xyz/wbsite/config/ThreadPoolConfig.java
index 764e30d..354e761 100644
--- a/admin/src/main/java/com/example/config/ThreadPoolConfig.java
+++ b/admin/src/main/java/xyz/wbsite/config/ThreadPoolConfig.java
@@ -1,4 +1,4 @@
-package com.example.config;
+package xyz.wbsite.config;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
diff --git a/admin/src/main/java/com/example/config/WebMvcConfig.java b/admin/src/main/java/xyz/wbsite/config/WebMvcConfig.java
similarity index 97%
rename from admin/src/main/java/com/example/config/WebMvcConfig.java
rename to admin/src/main/java/xyz/wbsite/config/WebMvcConfig.java
index 96f12b5..4a8d960 100644
--- a/admin/src/main/java/com/example/config/WebMvcConfig.java
+++ b/admin/src/main/java/xyz/wbsite/config/WebMvcConfig.java
@@ -1,11 +1,11 @@
-package com.example.config;
+package xyz.wbsite.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import com.example.frame.base.Token;
-import com.example.frame.utils.LocalData;
-import com.example.frame.utils.LogUtil;
+import xyz.wbsite.frame.base.Token;
+import xyz.wbsite.frame.utils.LocalData;
+import xyz.wbsite.frame.utils.LogUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
@@ -21,8 +21,6 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.List;
-
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
diff --git a/admin/src/main/java/com/example/frame/base/BaseEntity.java b/admin/src/main/java/xyz/wbsite/frame/base/BaseEntity.java
similarity index 98%
rename from admin/src/main/java/com/example/frame/base/BaseEntity.java
rename to admin/src/main/java/xyz/wbsite/frame/base/BaseEntity.java
index 9e2afd9..7a4f3ac 100644
--- a/admin/src/main/java/com/example/frame/base/BaseEntity.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/BaseEntity.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.Serializable;
diff --git a/admin/src/main/java/com/example/frame/base/BaseFindRequest.java b/admin/src/main/java/xyz/wbsite/frame/base/BaseFindRequest.java
similarity index 94%
rename from admin/src/main/java/com/example/frame/base/BaseFindRequest.java
rename to admin/src/main/java/xyz/wbsite/frame/base/BaseFindRequest.java
index 834c624..f7d804a 100644
--- a/admin/src/main/java/com/example/frame/base/BaseFindRequest.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/BaseFindRequest.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
/**
* BaseFindRequest - 基类
diff --git a/admin/src/main/java/com/example/frame/base/BaseFindResponse.java b/admin/src/main/java/xyz/wbsite/frame/base/BaseFindResponse.java
similarity index 94%
rename from admin/src/main/java/com/example/frame/base/BaseFindResponse.java
rename to admin/src/main/java/xyz/wbsite/frame/base/BaseFindResponse.java
index ce3b0aa..d351c2e 100644
--- a/admin/src/main/java/com/example/frame/base/BaseFindResponse.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/BaseFindResponse.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
import java.util.List;
diff --git a/admin/src/main/java/com/example/frame/base/BaseGetAllRequest.java b/admin/src/main/java/xyz/wbsite/frame/base/BaseGetAllRequest.java
similarity index 94%
rename from admin/src/main/java/com/example/frame/base/BaseGetAllRequest.java
rename to admin/src/main/java/xyz/wbsite/frame/base/BaseGetAllRequest.java
index 7fd7162..8f718fa 100644
--- a/admin/src/main/java/com/example/frame/base/BaseGetAllRequest.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/BaseGetAllRequest.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
/**
* BaseFindRequest - 基类
diff --git a/admin/src/main/java/com/example/frame/base/BaseRequest.java b/admin/src/main/java/xyz/wbsite/frame/base/BaseRequest.java
similarity index 79%
rename from admin/src/main/java/com/example/frame/base/BaseRequest.java
rename to admin/src/main/java/xyz/wbsite/frame/base/BaseRequest.java
index 848e47a..a24b7c9 100644
--- a/admin/src/main/java/com/example/frame/base/BaseRequest.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/BaseRequest.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
/**
* BaseRequest - 基类
diff --git a/admin/src/main/java/com/example/frame/base/BaseResponse.java b/admin/src/main/java/xyz/wbsite/frame/base/BaseResponse.java
similarity index 95%
rename from admin/src/main/java/com/example/frame/base/BaseResponse.java
rename to admin/src/main/java/xyz/wbsite/frame/base/BaseResponse.java
index cbcbe9d..8766d33 100644
--- a/admin/src/main/java/com/example/frame/base/BaseResponse.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/BaseResponse.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
import java.util.ArrayList;
import java.util.List;
diff --git a/admin/src/main/java/com/example/frame/base/BaseSearchRequest.java b/admin/src/main/java/xyz/wbsite/frame/base/BaseSearchRequest.java
similarity index 92%
rename from admin/src/main/java/com/example/frame/base/BaseSearchRequest.java
rename to admin/src/main/java/xyz/wbsite/frame/base/BaseSearchRequest.java
index 94ea40c..62cd20f 100644
--- a/admin/src/main/java/com/example/frame/base/BaseSearchRequest.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/BaseSearchRequest.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
/**
* BaseSearchRequest - 基类
diff --git a/admin/src/main/java/com/example/frame/base/BaseUpdateRequest.java b/admin/src/main/java/xyz/wbsite/frame/base/BaseUpdateRequest.java
similarity index 91%
rename from admin/src/main/java/com/example/frame/base/BaseUpdateRequest.java
rename to admin/src/main/java/xyz/wbsite/frame/base/BaseUpdateRequest.java
index eebc3ab..9a8578d 100644
--- a/admin/src/main/java/com/example/frame/base/BaseUpdateRequest.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/BaseUpdateRequest.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
/**
* BaseUpdateRequest - 基类
diff --git a/admin/src/main/java/com/example/frame/base/Control.java b/admin/src/main/java/xyz/wbsite/frame/base/Control.java
similarity index 89%
rename from admin/src/main/java/com/example/frame/base/Control.java
rename to admin/src/main/java/xyz/wbsite/frame/base/Control.java
index 2f862af..1074730 100644
--- a/admin/src/main/java/com/example/frame/base/Control.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/Control.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
import org.springframework.ui.Model;
diff --git a/admin/src/main/java/com/example/frame/base/Error.java b/admin/src/main/java/xyz/wbsite/frame/base/Error.java
similarity index 95%
rename from admin/src/main/java/com/example/frame/base/Error.java
rename to admin/src/main/java/xyz/wbsite/frame/base/Error.java
index 06fd8e0..72cc105 100644
--- a/admin/src/main/java/com/example/frame/base/Error.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/Error.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
/**
* Error - 错误基类
diff --git a/admin/src/main/java/com/example/frame/base/ErrorType.java b/admin/src/main/java/xyz/wbsite/frame/base/ErrorType.java
similarity index 88%
rename from admin/src/main/java/com/example/frame/base/ErrorType.java
rename to admin/src/main/java/xyz/wbsite/frame/base/ErrorType.java
index c99e7da..17fb52c 100644
--- a/admin/src/main/java/com/example/frame/base/ErrorType.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/ErrorType.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
/**
* ErrorType - 错误类型
diff --git a/admin/src/main/java/com/example/frame/base/FileUploadResponse.java b/admin/src/main/java/xyz/wbsite/frame/base/FileUploadResponse.java
similarity index 94%
rename from admin/src/main/java/com/example/frame/base/FileUploadResponse.java
rename to admin/src/main/java/xyz/wbsite/frame/base/FileUploadResponse.java
index 74fe555..ee7ee2c 100644
--- a/admin/src/main/java/com/example/frame/base/FileUploadResponse.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/FileUploadResponse.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
public class FileUploadResponse extends BaseResponse {
diff --git a/admin/src/main/java/com/example/frame/base/Message.java b/admin/src/main/java/xyz/wbsite/frame/base/Message.java
similarity index 91%
rename from admin/src/main/java/com/example/frame/base/Message.java
rename to admin/src/main/java/xyz/wbsite/frame/base/Message.java
index f373b82..be95b63 100644
--- a/admin/src/main/java/com/example/frame/base/Message.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/Message.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
public class Message {
diff --git a/admin/src/main/java/com/example/frame/base/MessageType.java b/admin/src/main/java/xyz/wbsite/frame/base/MessageType.java
similarity index 57%
rename from admin/src/main/java/com/example/frame/base/MessageType.java
rename to admin/src/main/java/xyz/wbsite/frame/base/MessageType.java
index 73406da..57a573b 100644
--- a/admin/src/main/java/com/example/frame/base/MessageType.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/MessageType.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
public enum MessageType {
diff --git a/admin/src/main/java/com/example/frame/base/Screen.java b/admin/src/main/java/xyz/wbsite/frame/base/Screen.java
similarity index 89%
rename from admin/src/main/java/com/example/frame/base/Screen.java
rename to admin/src/main/java/xyz/wbsite/frame/base/Screen.java
index 41c10e8..c2c66ed 100644
--- a/admin/src/main/java/com/example/frame/base/Screen.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/Screen.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
import org.springframework.ui.Model;
diff --git a/admin/src/main/java/com/example/frame/base/SortType.java b/admin/src/main/java/xyz/wbsite/frame/base/SortType.java
similarity index 83%
rename from admin/src/main/java/com/example/frame/base/SortType.java
rename to admin/src/main/java/xyz/wbsite/frame/base/SortType.java
index 3670757..3351d9d 100644
--- a/admin/src/main/java/com/example/frame/base/SortType.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/SortType.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
/**
* SortTypeEnum - 排序方式
diff --git a/admin/src/main/java/com/example/frame/base/Token.java b/admin/src/main/java/xyz/wbsite/frame/base/Token.java
similarity index 97%
rename from admin/src/main/java/com/example/frame/base/Token.java
rename to admin/src/main/java/xyz/wbsite/frame/base/Token.java
index 88d79a5..736790e 100644
--- a/admin/src/main/java/com/example/frame/base/Token.java
+++ b/admin/src/main/java/xyz/wbsite/frame/base/Token.java
@@ -1,4 +1,4 @@
-package com.example.frame.base;
+package xyz.wbsite.frame.base;
import java.io.Serializable;
import java.util.HashSet;
diff --git a/admin/src/main/java/com/example/frame/freemarker/Layout.java b/admin/src/main/java/xyz/wbsite/frame/freemarker/Layout.java
similarity index 95%
rename from admin/src/main/java/com/example/frame/freemarker/Layout.java
rename to admin/src/main/java/xyz/wbsite/frame/freemarker/Layout.java
index ea35850..4dea0cf 100644
--- a/admin/src/main/java/com/example/frame/freemarker/Layout.java
+++ b/admin/src/main/java/xyz/wbsite/frame/freemarker/Layout.java
@@ -1,7 +1,7 @@
-package com.example.frame.freemarker;
+package xyz.wbsite.frame.freemarker;
import java.io.File;
-import com.example.config.ActionConfig;
+import xyz.wbsite.config.ActionConfig;
import freemarker.template.TemplateModelException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -16,8 +16,8 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
-import com.example.frame.base.Control;
-import com.example.frame.utils.LocalData;
+import xyz.wbsite.frame.base.Control;
+import xyz.wbsite.frame.utils.LocalData;
/**
* 布局帮助类
diff --git a/admin/src/main/java/com/example/frame/freemarker/Uri.java b/admin/src/main/java/xyz/wbsite/frame/freemarker/Uri.java
similarity index 96%
rename from admin/src/main/java/com/example/frame/freemarker/Uri.java
rename to admin/src/main/java/xyz/wbsite/frame/freemarker/Uri.java
index 7489a53..7b74726 100644
--- a/admin/src/main/java/com/example/frame/freemarker/Uri.java
+++ b/admin/src/main/java/xyz/wbsite/frame/freemarker/Uri.java
@@ -1,4 +1,4 @@
-package com.example.frame.freemarker;
+package xyz.wbsite.frame.freemarker;
import freemarker.template.TemplateModelException;
import org.springframework.stereotype.Component;
diff --git a/admin/src/main/java/com/example/frame/freemarker/ViewNameTranslator.java b/admin/src/main/java/xyz/wbsite/frame/freemarker/ViewNameTranslator.java
similarity index 97%
rename from admin/src/main/java/com/example/frame/freemarker/ViewNameTranslator.java
rename to admin/src/main/java/xyz/wbsite/frame/freemarker/ViewNameTranslator.java
index d1f33d3..7494a4f 100644
--- a/admin/src/main/java/com/example/frame/freemarker/ViewNameTranslator.java
+++ b/admin/src/main/java/xyz/wbsite/frame/freemarker/ViewNameTranslator.java
@@ -1,6 +1,6 @@
-package com.example.frame.freemarker;
+package xyz.wbsite.frame.freemarker;
-import com.example.frame.utils.LocalData;
+import xyz.wbsite.frame.utils.LocalData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.DispatcherServlet;
diff --git a/admin/src/main/java/com/example/frame/utils/AESUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/AESUtil.java
similarity index 99%
rename from admin/src/main/java/com/example/frame/utils/AESUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/AESUtil.java
index 44d5106..7f42706 100644
--- a/admin/src/main/java/com/example/frame/utils/AESUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/AESUtil.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
diff --git a/admin/src/main/java/com/example/frame/utils/Base64Util.java b/admin/src/main/java/xyz/wbsite/frame/utils/Base64Util.java
similarity index 99%
rename from admin/src/main/java/com/example/frame/utils/Base64Util.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/Base64Util.java
index 253fddb..614c782 100644
--- a/admin/src/main/java/com/example/frame/utils/Base64Util.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/Base64Util.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import java.util.Arrays;
diff --git a/admin/src/main/java/com/example/frame/utils/CookieUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/CookieUtil.java
similarity index 96%
rename from admin/src/main/java/com/example/frame/utils/CookieUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/CookieUtil.java
index 3f2f512..11fe8d3 100644
--- a/admin/src/main/java/com/example/frame/utils/CookieUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/CookieUtil.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import javax.servlet.http.Cookie;
diff --git a/admin/src/main/java/com/example/frame/utils/FileUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/FileUtil.java
similarity index 99%
rename from admin/src/main/java/com/example/frame/utils/FileUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/FileUtil.java
index 55dd2c8..1450306 100644
--- a/admin/src/main/java/com/example/frame/utils/FileUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/FileUtil.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import java.io.*;
import java.net.MalformedURLException;
diff --git a/admin/src/main/java/com/example/frame/utils/IDgenerator.java b/admin/src/main/java/xyz/wbsite/frame/utils/IDgenerator.java
similarity index 98%
rename from admin/src/main/java/com/example/frame/utils/IDgenerator.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/IDgenerator.java
index 390ae19..ba4cf2a 100644
--- a/admin/src/main/java/com/example/frame/utils/IDgenerator.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/IDgenerator.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import java.io.BufferedReader;
import java.io.IOException;
diff --git a/admin/src/main/java/com/example/frame/utils/LocalData.java b/admin/src/main/java/xyz/wbsite/frame/utils/LocalData.java
similarity index 97%
rename from admin/src/main/java/com/example/frame/utils/LocalData.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/LocalData.java
index 6cee16a..3c5d210 100644
--- a/admin/src/main/java/com/example/frame/utils/LocalData.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/LocalData.java
@@ -1,6 +1,6 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
-import com.example.frame.base.Token;
+import xyz.wbsite.frame.base.Token;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
diff --git a/admin/src/main/java/com/example/frame/utils/LogUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/LogUtil.java
similarity index 98%
rename from admin/src/main/java/com/example/frame/utils/LogUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/LogUtil.java
index ea9bc7f..434d1dc 100644
--- a/admin/src/main/java/com/example/frame/utils/LogUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/LogUtil.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/admin/src/main/java/com/example/frame/utils/MD5Util.java b/admin/src/main/java/xyz/wbsite/frame/utils/MD5Util.java
similarity index 97%
rename from admin/src/main/java/com/example/frame/utils/MD5Util.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/MD5Util.java
index b5b4d23..6656176 100644
--- a/admin/src/main/java/com/example/frame/utils/MD5Util.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/MD5Util.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import com.fasterxml.jackson.core.TreeNode;
import java.security.MessageDigest;
diff --git a/admin/src/main/java/com/example/frame/utils/MapperUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/MapperUtil.java
similarity index 99%
rename from admin/src/main/java/com/example/frame/utils/MapperUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/MapperUtil.java
index 2746acd..bdaee60 100644
--- a/admin/src/main/java/com/example/frame/utils/MapperUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/MapperUtil.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
diff --git a/admin/src/main/java/com/example/frame/utils/Message.java b/admin/src/main/java/xyz/wbsite/frame/utils/Message.java
similarity index 96%
rename from admin/src/main/java/com/example/frame/utils/Message.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/Message.java
index d788d93..24c0d81 100644
--- a/admin/src/main/java/com/example/frame/utils/Message.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/Message.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
/**
diff --git a/admin/src/main/java/com/example/frame/utils/ProcessUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/ProcessUtil.java
similarity index 98%
rename from admin/src/main/java/com/example/frame/utils/ProcessUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/ProcessUtil.java
index a6248c3..039cac2 100644
--- a/admin/src/main/java/com/example/frame/utils/ProcessUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/ProcessUtil.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import java.awt.*;
import java.io.BufferedReader;
diff --git a/admin/src/main/java/com/example/frame/utils/RSAUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/RSAUtil.java
similarity index 99%
rename from admin/src/main/java/com/example/frame/utils/RSAUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/RSAUtil.java
index 9e4e207..daf49a3 100644
--- a/admin/src/main/java/com/example/frame/utils/RSAUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/RSAUtil.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
diff --git a/admin/src/main/java/xyz/wbsite/frame/utils/RequestUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/RequestUtil.java
new file mode 100644
index 0000000..a9fe557
--- /dev/null
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/RequestUtil.java
@@ -0,0 +1,79 @@
+package xyz.wbsite.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 "";
+ }
+ }
+}
diff --git a/admin/src/main/java/com/example/frame/utils/ValidationUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/ValidationUtil.java
similarity index 78%
rename from admin/src/main/java/com/example/frame/utils/ValidationUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/ValidationUtil.java
index 8f0cc6e..3e6ef64 100644
--- a/admin/src/main/java/com/example/frame/utils/ValidationUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/ValidationUtil.java
@@ -1,20 +1,13 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
-import com.example.frame.base.BaseRequest;
-import com.example.frame.base.BaseResponse;
-import com.example.frame.base.ErrorType;
+import xyz.wbsite.frame.base.BaseRequest;
+import xyz.wbsite.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.ErrorType;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* 验证工具类。提供一些通用简单的数据验证功能
diff --git a/admin/src/main/java/com/example/frame/utils/WebUtils.java b/admin/src/main/java/xyz/wbsite/frame/utils/WebUtils.java
similarity index 99%
rename from admin/src/main/java/com/example/frame/utils/WebUtils.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/WebUtils.java
index bf7da8f..e071ac2 100644
--- a/admin/src/main/java/com/example/frame/utils/WebUtils.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/WebUtils.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import javax.net.ssl.*;
import java.io.*;
diff --git a/admin/src/main/java/com/example/frame/utils/ZipUtil.java b/admin/src/main/java/xyz/wbsite/frame/utils/ZipUtil.java
similarity index 99%
rename from admin/src/main/java/com/example/frame/utils/ZipUtil.java
rename to admin/src/main/java/xyz/wbsite/frame/utils/ZipUtil.java
index 536254c..4707c1b 100644
--- a/admin/src/main/java/com/example/frame/utils/ZipUtil.java
+++ b/admin/src/main/java/xyz/wbsite/frame/utils/ZipUtil.java
@@ -1,4 +1,4 @@
-package com.example.frame.utils;
+package xyz.wbsite.frame.utils;
import java.io.*;
import java.util.Enumeration;
diff --git a/admin/src/main/java/com/example/frame/validation/Dict.java b/admin/src/main/java/xyz/wbsite/frame/validation/Dict.java
similarity index 91%
rename from admin/src/main/java/com/example/frame/validation/Dict.java
rename to admin/src/main/java/xyz/wbsite/frame/validation/Dict.java
index f96f392..fc253ed 100644
--- a/admin/src/main/java/com/example/frame/validation/Dict.java
+++ b/admin/src/main/java/xyz/wbsite/frame/validation/Dict.java
@@ -1,4 +1,4 @@
-package com.example.frame.validation;
+package xyz.wbsite.frame.validation;
import javax.validation.Constraint;
import javax.validation.Payload;
diff --git a/admin/src/main/java/com/example/frame/validation/DictValidator.java b/admin/src/main/java/xyz/wbsite/frame/validation/DictValidator.java
similarity index 96%
rename from admin/src/main/java/com/example/frame/validation/DictValidator.java
rename to admin/src/main/java/xyz/wbsite/frame/validation/DictValidator.java
index 10fa99a..aa8bd8f 100644
--- a/admin/src/main/java/com/example/frame/validation/DictValidator.java
+++ b/admin/src/main/java/xyz/wbsite/frame/validation/DictValidator.java
@@ -1,4 +1,4 @@
-package com.example.frame.validation;
+package xyz.wbsite.frame.validation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
diff --git a/admin/src/main/java/com/example/module/admin/ent/Mapping.java b/admin/src/main/java/xyz/wbsite/module/admin/ent/Mapping.java
similarity index 98%
rename from admin/src/main/java/com/example/module/admin/ent/Mapping.java
rename to admin/src/main/java/xyz/wbsite/module/admin/ent/Mapping.java
index 821bb51..af0457e 100644
--- a/admin/src/main/java/com/example/module/admin/ent/Mapping.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/ent/Mapping.java
@@ -1,4 +1,4 @@
-package com.example.module.admin.ent;
+package xyz.wbsite.module.admin.ent;
import com.fasterxml.jackson.annotation.JsonFormat;
import xyz.wbsite.wsqlite.anonation.TableField;
diff --git a/admin/src/main/java/com/example/module/admin/ent/NginxCtrl.java b/admin/src/main/java/xyz/wbsite/module/admin/ent/NginxCtrl.java
similarity index 94%
rename from admin/src/main/java/com/example/module/admin/ent/NginxCtrl.java
rename to admin/src/main/java/xyz/wbsite/module/admin/ent/NginxCtrl.java
index 83b04df..cf513b3 100644
--- a/admin/src/main/java/com/example/module/admin/ent/NginxCtrl.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/ent/NginxCtrl.java
@@ -1,7 +1,7 @@
-package com.example.module.admin.ent;
+package xyz.wbsite.module.admin.ent;
-import com.example.frame.utils.ProcessUtil;
+import xyz.wbsite.frame.utils.ProcessUtil;
import java.io.File;
diff --git a/admin/src/main/java/com/example/module/admin/ent/State.java b/admin/src/main/java/xyz/wbsite/module/admin/ent/State.java
similarity index 85%
rename from admin/src/main/java/com/example/module/admin/ent/State.java
rename to admin/src/main/java/xyz/wbsite/module/admin/ent/State.java
index 0f19da8..b678748 100644
--- a/admin/src/main/java/com/example/module/admin/ent/State.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/ent/State.java
@@ -1,4 +1,4 @@
-package com.example.module.admin.ent;
+package xyz.wbsite.module.admin.ent;
/**
* 运行状态
diff --git a/admin/src/main/java/com/example/module/admin/mgr/FreeMarkerManager.java b/admin/src/main/java/xyz/wbsite/module/admin/mgr/FreeMarkerManager.java
similarity index 98%
rename from admin/src/main/java/com/example/module/admin/mgr/FreeMarkerManager.java
rename to admin/src/main/java/xyz/wbsite/module/admin/mgr/FreeMarkerManager.java
index 3363e0b..b31519d 100644
--- a/admin/src/main/java/com/example/module/admin/mgr/FreeMarkerManager.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/mgr/FreeMarkerManager.java
@@ -1,4 +1,4 @@
-package com.example.module.admin.mgr;
+package xyz.wbsite.module.admin.mgr;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
diff --git a/admin/src/main/java/com/example/module/admin/mgr/MappingManager.java b/admin/src/main/java/xyz/wbsite/module/admin/mgr/MappingManager.java
similarity index 64%
rename from admin/src/main/java/com/example/module/admin/mgr/MappingManager.java
rename to admin/src/main/java/xyz/wbsite/module/admin/mgr/MappingManager.java
index b9d657e..23b7add 100644
--- a/admin/src/main/java/com/example/module/admin/mgr/MappingManager.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/mgr/MappingManager.java
@@ -1,8 +1,16 @@
-package com.example.module.admin.mgr;
+package xyz.wbsite.module.admin.mgr;
import com.example.module.admin.req.*;
import com.example.module.admin.rsp.*;
-import com.example.frame.base.Token;
+import xyz.wbsite.frame.base.Token;
+import xyz.wbsite.module.admin.req.MappingCreateRequest;
+import xyz.wbsite.module.admin.req.MappingDeleteRequest;
+import xyz.wbsite.module.admin.req.MappingFindRequest;
+import xyz.wbsite.module.admin.req.MappingUpdateRequest;
+import xyz.wbsite.module.admin.rsp.MappingCreateResponse;
+import xyz.wbsite.module.admin.rsp.MappingDeleteResponse;
+import xyz.wbsite.module.admin.rsp.MappingFindResponse;
+import xyz.wbsite.module.admin.rsp.MappingUpdateResponse;
/**
* 映射
diff --git a/admin/src/main/java/com/example/module/admin/mgr/MappingManagerImpl.java b/admin/src/main/java/xyz/wbsite/module/admin/mgr/MappingManagerImpl.java
similarity index 85%
rename from admin/src/main/java/com/example/module/admin/mgr/MappingManagerImpl.java
rename to admin/src/main/java/xyz/wbsite/module/admin/mgr/MappingManagerImpl.java
index c8a5e0c..6a45d5d 100644
--- a/admin/src/main/java/com/example/module/admin/mgr/MappingManagerImpl.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/mgr/MappingManagerImpl.java
@@ -1,19 +1,19 @@
-package com.example.module.admin.mgr;
-
-import com.example.frame.base.ErrorType;
-import com.example.frame.base.Token;
-import com.example.frame.utils.IDgenerator;
-import com.example.frame.utils.MapperUtil;
-import com.example.frame.utils.ValidationUtil;
-import com.example.module.admin.ent.Mapping;
-import com.example.module.admin.req.MappingCreateRequest;
-import com.example.module.admin.req.MappingDeleteRequest;
-import com.example.module.admin.req.MappingFindRequest;
-import com.example.module.admin.req.MappingUpdateRequest;
-import com.example.module.admin.rsp.MappingCreateResponse;
-import com.example.module.admin.rsp.MappingDeleteResponse;
-import com.example.module.admin.rsp.MappingFindResponse;
-import com.example.module.admin.rsp.MappingUpdateResponse;
+package xyz.wbsite.module.admin.mgr;
+
+import xyz.wbsite.frame.base.ErrorType;
+import xyz.wbsite.frame.base.Token;
+import xyz.wbsite.frame.utils.IDgenerator;
+import xyz.wbsite.frame.utils.MapperUtil;
+import xyz.wbsite.frame.utils.ValidationUtil;
+import xyz.wbsite.module.admin.ent.Mapping;
+import xyz.wbsite.module.admin.req.MappingCreateRequest;
+import xyz.wbsite.module.admin.req.MappingDeleteRequest;
+import xyz.wbsite.module.admin.req.MappingFindRequest;
+import xyz.wbsite.module.admin.req.MappingUpdateRequest;
+import xyz.wbsite.module.admin.rsp.MappingCreateResponse;
+import xyz.wbsite.module.admin.rsp.MappingDeleteResponse;
+import xyz.wbsite.module.admin.rsp.MappingFindResponse;
+import xyz.wbsite.module.admin.rsp.MappingUpdateResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xyz.wbsite.wsqlite.ObjectClient;
diff --git a/admin/src/main/java/com/example/module/admin/req/LoginRequest.java b/admin/src/main/java/xyz/wbsite/module/admin/req/LoginRequest.java
similarity index 84%
rename from admin/src/main/java/com/example/module/admin/req/LoginRequest.java
rename to admin/src/main/java/xyz/wbsite/module/admin/req/LoginRequest.java
index b3a7e05..f532f6e 100644
--- a/admin/src/main/java/com/example/module/admin/req/LoginRequest.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/req/LoginRequest.java
@@ -1,9 +1,8 @@
-package com.example.module.admin.req;
+package xyz.wbsite.module.admin.req;
-import com.example.frame.base.BaseRequest;
+import xyz.wbsite.frame.base.BaseRequest;
import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
/**
* MappingCreateRequest - 映射新增
diff --git a/admin/src/main/java/com/example/module/admin/req/MappingCreateRequest.java b/admin/src/main/java/xyz/wbsite/module/admin/req/MappingCreateRequest.java
similarity index 85%
rename from admin/src/main/java/com/example/module/admin/req/MappingCreateRequest.java
rename to admin/src/main/java/xyz/wbsite/module/admin/req/MappingCreateRequest.java
index 2f274ad..143ccfa 100644
--- a/admin/src/main/java/com/example/module/admin/req/MappingCreateRequest.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/req/MappingCreateRequest.java
@@ -1,17 +1,10 @@
-package com.example.module.admin.req;
+package xyz.wbsite.module.admin.req;
-import com.example.frame.base.BaseRequest;
+import xyz.wbsite.frame.base.BaseRequest;
import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
-import org.hibernate.validator.constraints.Length;
-import xyz.wbsite.wsqlite.anonation.TableField;
-
-import java.util.regex.Matcher;
-
/**
* MappingCreateRequest - 映射新增
*
diff --git a/admin/src/main/java/com/example/module/admin/req/MappingDeleteRequest.java b/admin/src/main/java/xyz/wbsite/module/admin/req/MappingDeleteRequest.java
similarity index 83%
rename from admin/src/main/java/com/example/module/admin/req/MappingDeleteRequest.java
rename to admin/src/main/java/xyz/wbsite/module/admin/req/MappingDeleteRequest.java
index 6c65a34..d5531ce 100644
--- a/admin/src/main/java/com/example/module/admin/req/MappingDeleteRequest.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/req/MappingDeleteRequest.java
@@ -1,6 +1,6 @@
-package com.example.module.admin.req;
+package xyz.wbsite.module.admin.req;
-import com.example.frame.base.BaseUpdateRequest;
+import xyz.wbsite.frame.base.BaseUpdateRequest;
import javax.validation.constraints.NotNull;
/**
diff --git a/admin/src/main/java/com/example/module/admin/req/MappingFindRequest.java b/admin/src/main/java/xyz/wbsite/module/admin/req/MappingFindRequest.java
similarity index 79%
rename from admin/src/main/java/com/example/module/admin/req/MappingFindRequest.java
rename to admin/src/main/java/xyz/wbsite/module/admin/req/MappingFindRequest.java
index 049846c..2ccdc56 100644
--- a/admin/src/main/java/com/example/module/admin/req/MappingFindRequest.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/req/MappingFindRequest.java
@@ -1,6 +1,6 @@
-package com.example.module.admin.req;
+package xyz.wbsite.module.admin.req;
-import com.example.frame.base.BaseFindRequest;
+import xyz.wbsite.frame.base.BaseFindRequest;
/**
* MappingRequest - 映射查询
diff --git a/admin/src/main/java/com/example/module/admin/req/MappingUpdateRequest.java b/admin/src/main/java/xyz/wbsite/module/admin/req/MappingUpdateRequest.java
similarity index 89%
rename from admin/src/main/java/com/example/module/admin/req/MappingUpdateRequest.java
rename to admin/src/main/java/xyz/wbsite/module/admin/req/MappingUpdateRequest.java
index c186e64..d6933c0 100644
--- a/admin/src/main/java/com/example/module/admin/req/MappingUpdateRequest.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/req/MappingUpdateRequest.java
@@ -1,14 +1,10 @@
-package com.example.module.admin.req;
+package xyz.wbsite.module.admin.req;
-import com.example.frame.base.BaseUpdateRequest;
+import xyz.wbsite.frame.base.BaseUpdateRequest;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
-import org.hibernate.validator.constraints.Length;
-import xyz.wbsite.wsqlite.anonation.TableField;
-
-import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
/**
diff --git a/admin/src/main/java/xyz/wbsite/module/admin/rsp/LoginResponse.java b/admin/src/main/java/xyz/wbsite/module/admin/rsp/LoginResponse.java
new file mode 100644
index 0000000..2376f5b
--- /dev/null
+++ b/admin/src/main/java/xyz/wbsite/module/admin/rsp/LoginResponse.java
@@ -0,0 +1,9 @@
+package xyz.wbsite.module.admin.rsp;
+
+import xyz.wbsite.frame.base.BaseResponse;
+
+
+public class LoginResponse extends BaseResponse {
+
+
+}
diff --git a/admin/src/main/java/com/example/module/admin/rsp/MappingCreateResponse.java b/admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingCreateResponse.java
similarity index 79%
rename from admin/src/main/java/com/example/module/admin/rsp/MappingCreateResponse.java
rename to admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingCreateResponse.java
index bf966c1..c604407 100644
--- a/admin/src/main/java/com/example/module/admin/rsp/MappingCreateResponse.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingCreateResponse.java
@@ -1,6 +1,6 @@
-package com.example.module.admin.rsp;
+package xyz.wbsite.module.admin.rsp;
-import com.example.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.BaseResponse;
/**
* MappingCreateResponse - 映射
diff --git a/admin/src/main/java/com/example/module/admin/rsp/MappingDeleteResponse.java b/admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingDeleteResponse.java
similarity index 81%
rename from admin/src/main/java/com/example/module/admin/rsp/MappingDeleteResponse.java
rename to admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingDeleteResponse.java
index 5d6687c..daa1eba 100644
--- a/admin/src/main/java/com/example/module/admin/rsp/MappingDeleteResponse.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingDeleteResponse.java
@@ -1,6 +1,6 @@
-package com.example.module.admin.rsp;
+package xyz.wbsite.module.admin.rsp;
-import com.example.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.BaseResponse;
/**
* MappingDeleteResponse - 映射
diff --git a/admin/src/main/java/com/example/module/admin/rsp/MappingFindResponse.java b/admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingFindResponse.java
similarity index 56%
rename from admin/src/main/java/com/example/module/admin/rsp/MappingFindResponse.java
rename to admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingFindResponse.java
index 93e074b..a1ddc80 100644
--- a/admin/src/main/java/com/example/module/admin/rsp/MappingFindResponse.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingFindResponse.java
@@ -1,8 +1,8 @@
-package com.example.module.admin.rsp;
+package xyz.wbsite.module.admin.rsp;
-import com.example.frame.base.BaseFindResponse;
-import com.example.module.admin.ent.Mapping;
+import xyz.wbsite.frame.base.BaseFindResponse;
+import xyz.wbsite.module.admin.ent.Mapping;
/**
* MappingFindResponse - 映射
diff --git a/admin/src/main/java/com/example/module/admin/rsp/MappingUpdateResponse.java b/admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingUpdateResponse.java
similarity index 81%
rename from admin/src/main/java/com/example/module/admin/rsp/MappingUpdateResponse.java
rename to admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingUpdateResponse.java
index 7aaa0eb..4d524b1 100644
--- a/admin/src/main/java/com/example/module/admin/rsp/MappingUpdateResponse.java
+++ b/admin/src/main/java/xyz/wbsite/module/admin/rsp/MappingUpdateResponse.java
@@ -1,6 +1,6 @@
-package com.example.module.admin.rsp;
+package xyz.wbsite.module.admin.rsp;
-import com.example.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.BaseResponse;
/**
* MappingUpdateResponse - 映射
diff --git a/admin/src/main/resources/templates/nginx.conf.ftl b/admin/src/main/resources/templates/nginx.conf.ftl
index ad7566b..c7d1e8c 100644
--- a/admin/src/main/resources/templates/nginx.conf.ftl
+++ b/admin/src/main/resources/templates/nginx.conf.ftl
@@ -34,20 +34,9 @@ http {
<#list services?keys as key>
server {
- listen ${key} <#if key == '443'>ssl#if>;
+ listen ${key};
server_name wbsite.xyz;
- <#if key == '443'>
- ssl on;
- ssl_certificate 3380768_www.wbsite.xyz.crt;
- ssl_certificate_key 3380768_www.wbsite.xyz.key;
- ssl_session_timeout 5m;
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
- ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
- ssl_prefer_server_ciphers on;
- #if>
- access_log logs/host.access.log main;
-
<#list services[key] as mapping>
<#if mapping.type="HTTP">
location ${mapping.context} {
@@ -65,8 +54,6 @@ http {
index index.html index.htm;
autoindex on;
}
-<#elseif mapping.type="转HTTPS">
- return 301 https://$server_name$request_uri;
#if>
#list>
diff --git a/admin/src/main/resources/templates/screen/mapping.ftl b/admin/src/main/resources/templates/screen/mapping.ftl
index a61820a..28c5f69 100644
--- a/admin/src/main/resources/templates/screen/mapping.ftl
+++ b/admin/src/main/resources/templates/screen/mapping.ftl
@@ -149,8 +149,6 @@
placeholder="代理地址http://">
-
-
4.0.0
-
-
- admin
- wsqlite
-
-
org.springframework.boot
spring-boot-starter-parent
2.1.2.RELEASE
-
xyz.wbsite
- nginx-admin-parent
- 1.0-SNAPSHOT
- pom
+ nginx-admin
+ 0.0.1-SNAPSHOT
+ jar
+
+ nginx-admin
+ project for Spring Boot
UTF-8
@@ -32,22 +27,86 @@
1.1.0
5.5.1
Greenwich.RC2
- 1.0-SNAPSHOT
+ 3.8
- aliyun-repos
- http://maven.aliyun.com/nexus/content/groups/public/
-
- false
-
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+
+
+
+ org.mybatis.caches
+ mybatis-ehcache
+
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-freemarker
+
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ provided
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ net.sf.dozer
+ dozer
+
+
+
+ org.apache.poi
+ poi-ooxml
+
+
+
+
+ org.xerial
+ sqlite-jdbc
+ 3.21.0.1
+
+
+
+
-
org.springframework.cloud
spring-cloud-dependencies
@@ -55,24 +114,94 @@
pom
import
-
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+ ${pagehelper-version}
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ ${mybatis-version}
+
+
+ org.mybatis.caches
+ mybatis-ehcache
+ ${ehcache-version}
+
net.sf.dozer
dozer
${dozer-version}
-
-
- commons-io
- commons-io
- ${commons-io-version}
-
-
- xyz.wbsite
- wsqlite
- ${wsqlite}
+ org.apache.poi
+ poi-ooxml
+ ${poi-ooxml-version}
-
\ No newline at end of file
+
+
+
+ ${artifactId}-${version}
+
+ src/main/java
+
+ src/test/java
+
+
+ src/main/resources
+
+
+
+ src/main/java
+
+ **/*Mapper.xml
+
+
+
+
+ ${basedir}/src/main/resources/lib
+ BOOT-INF/lib/
+
+ *.jar
+
+
+
+
+ ${basedir}/src/main/resources
+
+ *.bat
+
+ ${basedir}/target
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+
+
+ ${project.basedir}/src/main/resources/lib
+ WEB-INF/lib
+
+ *.jar
+
+
+
+
+
+
+
+
diff --git a/src/main/java/xyz/wbsite/Application.java b/src/main/java/xyz/wbsite/Application.java
new file mode 100644
index 0000000..f2ecd72
--- /dev/null
+++ b/src/main/java/xyz/wbsite/Application.java
@@ -0,0 +1,22 @@
+package xyz.wbsite;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import xyz.wbsite.frame.auth.LocalData;
+
+@SpringBootApplication
+@EnableAutoConfiguration
+public class Application extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(Application.class);
+ }
+
+ public static void main(String[] args) {
+ LocalData.setApplicationContext(SpringApplication.run(Application.class, args));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/action/GlobalController.java b/src/main/java/xyz/wbsite/action/GlobalController.java
new file mode 100644
index 0000000..5c304a5
--- /dev/null
+++ b/src/main/java/xyz/wbsite/action/GlobalController.java
@@ -0,0 +1,454 @@
+package xyz.wbsite.action;
+
+import com.fasterxml.jackson.core.TreeNode;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.error.ErrorController;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
+import xyz.wbsite.config.ActionConfig;
+import xyz.wbsite.frame.auth.LocalData;
+import xyz.wbsite.frame.base.BaseRequest;
+import xyz.wbsite.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.ErrorType;
+import xyz.wbsite.frame.base.Screen;
+import xyz.wbsite.frame.auth.Token;
+import xyz.wbsite.frame.utils.AESUtil;
+import xyz.wbsite.frame.utils.LogUtil;
+import xyz.wbsite.frame.utils.MD5Util;
+import xyz.wbsite.frame.utils.MapperUtil;
+import xyz.wbsite.frame.utils.RequestUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Locale;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 全局请求Controller,如果无特殊请求,则不需再增加其他Controller
+ * 全局htm后缀入口{@link GlobalController#action(Model, HttpServletRequest, HttpServletResponse)}
+ * 全局ajax入口{@link GlobalController#ajax(String, String, String, HttpServletRequest, HttpServletResponse, String, MultipartFile)}
+ * 全局异常捕捉{@link GlobalController#exceptionHandler(HttpServletRequest, HttpServletResponse, Model, Exception)}
+ * 全局消息订阅{@link GlobalController#sse(String)}
+ *
+ * 说明Request命名规则,驼峰式命名
+ * Api#Example#Request ==> 目标#动作#Request
+ *
+ * @author author
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Controller
+@ControllerAdvice
+public class GlobalController implements ErrorController {
+
+ @Value("${server.servlet.context-path}")
+ private String context;
+ @Value("${web.home.page}")
+ private String homePage;
+ @Value("${web.login.page}")
+ private String loginPage;
+ @Autowired
+ private FreeMarkerViewResolver viewResolver;
+
+ /**
+ * 全局异常捕捉
+ *
+ * @param request
+ * @param response
+ * @param exception 要捕获的异常
+ * @return
+ */
+ @ExceptionHandler(Exception.class)
+ public String exceptionHandler(HttpServletRequest request, HttpServletResponse response, Model model, Exception exception) {
+ StringBuffer msg = new StringBuffer("");
+ if (exception != null) {
+ msg = new StringBuffer("");
+ String message = exception.toString();
+ int length = exception.getStackTrace().length;
+ if (length > 0) {
+ msg.append("").append(message).append("
");
+ for (int i = 0; i < length; i++) {
+ msg.append("").append(exception.getStackTrace()[i]).append("
");
+ }
+ } else {
+ msg.append(message);
+ }
+ }
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ model.addAttribute("msg", msg.toString());
+ return "500";
+ }
+
+ private final static String ERROR_PATH = "/error";
+
+ @Override
+ public String getErrorPath() {
+ return ERROR_PATH;
+ }
+
+ @RequestMapping(value = ERROR_PATH)
+ public String error(HttpServletRequest request, HttpServletResponse response) {
+ switch (response.getStatus()) {
+ case 404:
+ return "404";
+ case 403:
+ String errorUrl = RequestUtil.getErrorUrl(request);
+ errorUrl = errorUrl.replaceFirst(context, "");
+ if ((errorUrl.equals(homePage) || errorUrl.equals("/")) && LocalData.getToken() == null) {
+ try {
+ response.sendRedirect(context + loginPage);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return "403";
+ case 500:
+ return "500";
+ default:
+ return "403";
+ }
+ }
+
+ @RequestMapping("/")
+ public String home() {
+ Token token = LocalData.getToken();
+ if (token == null) {
+ return "redirect:" + loginPage;
+ } else {
+ return "redirect:" + homePage;
+ }
+ }
+
+ /**
+ * 当未明确指定控制器时,走该请求,默认返回对应的layout布局和screen视图
+ * 当需要使用layout时,不需要返回值,ViewNameTranslator会处理对应关系
+ *
+ * @param model
+ * @param request
+ */
+ @RequestMapping({"/**/*.htm"})
+ public String action(Model model, HttpServletRequest request, HttpServletResponse response) {
+ String servletPath = request.getServletPath();// /**/*.htm
+ String layout = "/layout/default";
+ String action = LocalData.getAction();// **/*
+
+ Pattern compile = Pattern.compile("^/(.+)\\.htm");
+ Matcher matcher = compile.matcher(servletPath);
+ if (matcher.find()) {
+ action = matcher.group(1);
+ LocalData.setAction(action);
+ }
+
+ try {
+ LocaleResolver localeResolver = (LocaleResolver) request.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE);
+ Locale locale = localeResolver.resolveLocale(request);
+
+ {//查询screen
+ String[] split = action.split("/");
+ StringBuilder sb = new StringBuilder("");
+ sb.append("screen");
+ for (int i = 0; i < split.length; i++) {
+ sb.append(File.separator);
+ sb.append(split[i]);
+ }
+ layout = sb.toString();
+ View view = viewResolver.resolveViewName(layout, locale);
+ if (view == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND,"");
+ return null;
+ }
+
+ // 尝试执行Screen执行器(服务器渲染),并返回视图模板
+ try {
+ String beanClassName = (ActionConfig.SCREEN_PREFIX + action).toLowerCase();
+ Screen screenExec = LocalData.getApplicationContext().getBean(beanClassName, Screen.class);
+ screenExec.exec(model, request, response);
+
+ if (response.getStatus() != HttpServletResponse.SC_OK) {
+ response.sendError(response.getStatus(),"");
+ return null;
+ }
+ } catch (BeansException e) {
+
+ }
+ }
+
+ {//查找layout
+ String[] split = action.split("/");
+
+ int lt = split.length;
+ while (lt > 0) {
+
+ StringBuilder sb = new StringBuilder("");
+ sb.append("layout");
+ for (int i = 0; i < lt - 1; i++) {
+ sb.append(File.separator);
+ sb.append(split[i]);
+ }
+
+ layout = sb.toString() + File.separator + split[split.length - 1];
+
+ View view = viewResolver.resolveViewName(layout, locale);
+ //无法找到对应layout,使用默认layout
+ if (view == null) {
+ layout = sb.toString() + File.separator + "default";
+ View defaultView = viewResolver.resolveViewName(layout, locale);
+ if (null == defaultView && lt == 1) {
+ System.err.println("can not find layout/default.ftl");
+ } else if (null == defaultView) {
+ lt--;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ } catch (Exception e) {
+ return exceptionHandler(request, response, model, e);
+ }
+
+ // todo 可在此获取共性数据(也可以在全局拦截器GlobalHandlerInterceptor、拦截器作用域比此更高),
+ // todo 例如用户信息等。其他业务数据在页面渲染后通过Ajax请求
+ return layout;
+ }
+
+ @RequestMapping("/ajax/{module}/{target}/{method}")
+ @ResponseBody
+ public Object ajax(
+ @PathVariable String module,
+ @PathVariable String target,
+ @PathVariable String method,
+ HttpServletRequest httpServletRequest,
+ HttpServletResponse httpServletResponse,
+ @RequestBody(required = false) String data,
+ @RequestParam(name = "file", required = false) MultipartFile file) {
+ try {
+ String beanClassName = (ActionConfig.AJAX_PREFIX + module + "/" + target).toLowerCase();
+ Object ajax = LocalData.getApplicationContext().getBean(beanClassName);
+
+ Class ajaxClass = ajax.getClass();
+
+ Method[] methods = ajaxClass.getDeclaredMethods();
+
+ Method methodC = null;
+ for (Method meth : methods) {
+ if (meth.getName().equals(method)) {
+ methodC = meth;
+ }
+ }
+
+ if (methodC == null) {
+ BaseResponse baseResponse = new BaseResponse();
+ baseResponse.addError(ErrorType.BUSINESS_ERROR, "未找到对应的方法!");
+ return baseResponse;
+ }
+
+ Parameter[] parameters = methodC.getParameters();
+ Object[] arg = new Object[parameters.length];
+
+ for (int i = 0; i < parameters.length; i++) {
+ Parameter parameter = parameters[i];
+ if (parameter.getType() == HttpServletRequest.class) {
+ arg[i] = httpServletRequest;
+ } else if (parameter.getType() == HttpServletResponse.class) {
+ arg[i] = httpServletResponse;
+ } else if (parameter.getType() == TreeNode.class) {
+ arg[i] = MapperUtil.toTree(data);
+ } else if (parameter.getType() == String.class) {
+ arg[i] = data;
+ } else if (parameter.getType() == MultipartFile.class) {
+ arg[i] = file;
+ } else if (BaseRequest.class.isAssignableFrom(parameter.getType())) {
+ arg[i] = MapperUtil.toJava(data, parameter.getType());
+ } else if (parameter.getType() == Token.class) {
+ arg[i] = LocalData.getToken();
+ } else {
+ arg[i] = null;
+ }
+ }
+ return methodC.invoke(ajax, arg);
+ } catch (BeansException e) {
+ e.printStackTrace();
+ BaseResponse baseResponse = new BaseResponse();
+ baseResponse.addError(ErrorType.BUSINESS_ERROR, "未找到对应的目标!");
+ return baseResponse;
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ BaseResponse baseResponse = new BaseResponse();
+ baseResponse.addError(ErrorType.BUSINESS_ERROR, "方法执必须公开!");
+ return baseResponse;
+ } catch (InvocationTargetException e) {
+ e.getTargetException().printStackTrace();
+ BaseResponse baseResponse = new BaseResponse();
+ baseResponse.addError(ErrorType.BUSINESS_ERROR, "方法执行错误[" + e.getTargetException().getMessage() + "]");
+ return baseResponse;
+ }
+ }
+
+
+ @RequestMapping(path = "/api/{module}/{target}/{method}", method = RequestMethod.POST)
+ @ResponseBody
+ public String api(
+ @PathVariable String module,
+ @PathVariable String target,
+ @PathVariable String method,
+ @RequestParam(required = false) String appKey,
+ @RequestParam(required = false) String sign,
+ @RequestParam(required = false) Long timestamp,
+ @RequestParam(required = false) String token,
+ @RequestParam(required = false) String encryptData,
+ HttpServletRequest httpServletRequest,
+ HttpServletResponse httpServletResponse) {
+ BaseResponse response = new BaseResponse();
+ if (appKey == null) {
+ response.addError(ErrorType.BUSINESS_ERROR, "应用码参数[appKey]不存在!");
+ return MapperUtil.toJson(response);
+ } else if (sign == null) {
+ response.addError(ErrorType.BUSINESS_ERROR, "签名参数[sign]不存在!");
+ return MapperUtil.toJson(response);
+ } else if (timestamp == null) {
+ response.addError(ErrorType.BUSINESS_ERROR, "时间戳参数[timestamp]不存在!");
+ return MapperUtil.toJson(response);
+ }
+
+ String data = null;
+ String appSecret = "1234567890123456";
+ // 解码
+ try {
+ data = AESUtil.decrypt2String(encryptData, appSecret);
+ } catch (Exception e) {
+ response.addError(ErrorType.BUSINESS_ERROR, "解码失败,请确认编码是否正确!");
+ return MapperUtil.toJson(response);
+ }
+
+ // 验证签名
+ String sign_ = MD5Util.encode(appSecret + data + timestamp);
+ if (!sign_.equals(sign)) {
+ response.addError(ErrorType.BUSINESS_ERROR, "签名验证失败!");
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ // 时效性验证
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - timestamp > 2 * 60 * 1000) {
+ response.addError(ErrorType.BUSINESS_ERROR, "请求过期, 或本地时间错误!");
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ // 权限验证
+ if (!LocalData.getToken().hasRes(httpServletRequest.getServletPath())) {
+ response.addError(ErrorType.BUSINESS_ERROR, "[" + httpServletRequest.getServletPath() + "]未授权的资源!");
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ // 开始处理业务
+ try {
+ String beanClassName = (ActionConfig.API_PREFIX + module + "/" + target).toLowerCase();
+ Object ajax = LocalData.getApplicationContext().getBean(beanClassName);
+ Class ajaxClass = ajax.getClass();
+ Method[] methods = ajaxClass.getDeclaredMethods();
+
+ Method methodC = null;
+ for (Method meth : methods) {
+ if (meth.getName().equals(method)) {
+ methodC = meth;
+ }
+ }
+
+ if (methodC == null) {
+ response.addError(ErrorType.BUSINESS_ERROR, "未找到对应的方法!");
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ Parameter[] parameters = methodC.getParameters();
+ Object[] arg = new Object[parameters.length];
+
+ for (int i = 0; i < parameters.length; i++) {
+ Parameter parameter = parameters[i];
+ if (parameter.getType() == HttpServletRequest.class) {
+ arg[i] = httpServletRequest;
+ } else if (parameter.getType() == HttpServletResponse.class) {
+ arg[i] = httpServletResponse;
+ } else if (BaseRequest.class.isAssignableFrom(parameter.getType())) {
+ arg[i] = MapperUtil.toJava(data, parameter.getType());
+ } else if (parameter.getType() == TreeNode.class) {
+ arg[i] = MapperUtil.toTree(data);
+ } else if (parameter.getType() == Token.class) {
+ arg[i] = LocalData.getToken();
+ } else {
+ arg[i] = null;
+ }
+ }
+ response = (BaseResponse) methodC.invoke(ajax, arg);
+ } catch (BeansException e) {
+ e.printStackTrace();
+ response.addError(ErrorType.BUSINESS_ERROR, "未找到对应的目标!");
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ response.addError(ErrorType.BUSINESS_ERROR, "方法执必须公开!");
+ } catch (InvocationTargetException e) {
+ LogUtil.dumpException(e.getTargetException());
+ e.getTargetException().printStackTrace();
+ response.addError(ErrorType.BUSINESS_ERROR, "方法执行错误[" + e.getTargetException().getMessage() + "]");
+ }
+ return AESUtil.encrypt2Base64(MapperUtil.toJson(response).getBytes(), appSecret);
+ }
+
+ private static ConcurrentHashMap sseMap = new ConcurrentHashMap();
+
+ /**
+ * Sse推送服务,服务器向js推送自定义消息
+ * Sse容器{@link GlobalController#sseMap}
+ * Sse批量推送{@link GlobalController#pushAll}
+ */
+ @RequestMapping(value = "/sse/{userId}", produces = "text/event-stream;charset=UTF-8")
+ public SseEmitter sse(@PathVariable String userId) {
+ SseEmitter sseEmitter = new SseEmitter(10000000L);
+ if (sseMap.get(userId) != null) {
+ sseMap.remove(userId);
+ }
+ sseMap.put(userId, sseEmitter);
+ return sseEmitter;
+ }
+
+ /**
+ * Sse批量推送
+ *
+ * @param data 推送对象
+ */
+ public static void pushAll(Object data) {
+ for (String s : sseMap.keySet()) {
+ try {
+ sseMap.get(s).send(MapperUtil.toJson(data), MediaType.APPLICATION_JSON);
+ } catch (IOException e) {
+ sseMap.remove(s);
+ }
+ }
+ }
+}
diff --git a/src/main/java/xyz/wbsite/action/ajax/conf/MappingAjax.java b/src/main/java/xyz/wbsite/action/ajax/conf/MappingAjax.java
new file mode 100644
index 0000000..1cc0ff2
--- /dev/null
+++ b/src/main/java/xyz/wbsite/action/ajax/conf/MappingAjax.java
@@ -0,0 +1,56 @@
+package xyz.wbsite.action.ajax.conf;
+
+import com.fasterxml.jackson.core.TreeNode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.multipart.MultipartFile;
+import xyz.wbsite.frame.excel.WExcel;
+import xyz.wbsite.frame.utils.LogUtil;
+import xyz.wbsite.frame.auth.LocalData;
+import xyz.wbsite.frame.base.ErrorType;
+import xyz.wbsite.frame.utils.MapperUtil;
+import xyz.wbsite.frame.base.BaseResponse;
+import xyz.wbsite.frame.utils.ResponseUtil;
+import xyz.wbsite.frame.utils.ValidationUtil;
+import xyz.wbsite.frame.excel.exception.ReadErrorException;
+import xyz.wbsite.frame.excel.exception.TemplateNotMatchException;
+import xyz.wbsite.module.conf.ent.Mapping;
+import xyz.wbsite.module.conf.mgr.MappingManager;
+import xyz.wbsite.module.conf.req.MappingCreateRequest;
+import xyz.wbsite.module.conf.req.MappingDeleteRequest;
+import xyz.wbsite.module.conf.req.MappingFindRequest;
+import xyz.wbsite.module.conf.req.MappingGetRequest;
+import xyz.wbsite.module.conf.req.MappingUpdateRequest;
+import xyz.wbsite.module.conf.rsp.MappingCreateResponse;
+import xyz.wbsite.module.conf.rsp.MappingDeleteResponse;
+import xyz.wbsite.module.conf.rsp.MappingFindResponse;
+import xyz.wbsite.module.conf.rsp.MappingGetResponse;
+import xyz.wbsite.module.conf.rsp.MappingUpdateResponse;
+
+import java.io.IOException;
+import java.util.List;
+
+public class MappingAjax{
+
+ @Autowired
+ private MappingManager mappingManager;
+
+ public MappingCreateResponse create(MappingCreateRequest request) {
+ return mappingManager.create(request, LocalData.getToken());
+ }
+
+ public MappingDeleteResponse delete(MappingDeleteRequest request) {
+ return mappingManager.delete(request, LocalData.getToken());
+ }
+
+ public MappingUpdateResponse update(MappingUpdateRequest request) {
+ return mappingManager.update(request, LocalData.getToken());
+ }
+
+ public MappingFindResponse find(MappingFindRequest request) {
+ return mappingManager.find(request, LocalData.getToken());
+ }
+
+ public MappingGetResponse get(MappingGetRequest request) {
+ return mappingManager.get(request, LocalData.getToken());
+ }
+}
diff --git a/src/main/java/xyz/wbsite/action/ajax/system/UserAjax.java b/src/main/java/xyz/wbsite/action/ajax/system/UserAjax.java
new file mode 100644
index 0000000..cf2fefa
--- /dev/null
+++ b/src/main/java/xyz/wbsite/action/ajax/system/UserAjax.java
@@ -0,0 +1,63 @@
+package xyz.wbsite.action.ajax.system;
+
+import org.springframework.beans.factory.annotation.Value;
+import xyz.wbsite.frame.auth.LocalData;
+import xyz.wbsite.frame.auth.Token;
+import xyz.wbsite.frame.base.ErrorType;
+import xyz.wbsite.frame.utils.CookieUtil;
+import xyz.wbsite.frame.utils.IDgenerator;
+import xyz.wbsite.frame.utils.MD5Util;
+import xyz.wbsite.frame.utils.ValidationUtil;
+import xyz.wbsite.module.system.req.UserLoginRequest;
+import xyz.wbsite.module.system.req.UserLogoutRequest;
+import xyz.wbsite.module.system.rsp.UserLoginResponse;
+import xyz.wbsite.module.system.rsp.UserLogoutResponse;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Calendar;
+import java.util.Date;
+
+public class UserAjax {
+
+ @Value("${web.url.auth.admin}")
+ private String admin;
+ @Value("${web.url.auth.pwd}")
+ private String pwd;
+
+ public UserLoginResponse login(UserLoginRequest request, Token token, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
+ UserLoginResponse response = new UserLoginResponse();
+
+ ValidationUtil.validate(request, response);
+ if (response.hasError()) {
+ return response;
+ }
+
+ if (request.getUsername().equals(admin)) {//超级管理员登录
+ String generatePwd = MD5Util.generatePwd(request.getPassword());
+ if (!generatePwd.equals(pwd)) {
+ response.addError(ErrorType.BUSINESS_ERROR, "用户名或密码错误!");
+ } else {
+ Date current = new Date();
+ Calendar instance = Calendar.getInstance();
+ instance.setTime(current);
+ instance.add(Calendar.HOUR_OF_DAY, 1);//默认一个小时内有效
+
+ Token sysToken = LocalData.getSysToken();
+ sysToken.setToken(IDgenerator.nextUUID());
+
+ Cookie cookie = CookieUtil.newCookie("token", sysToken.getToken());
+ httpServletResponse.addCookie(cookie);
+ response.setToken(sysToken.getToken());
+ }
+ }
+ return response;
+ }
+
+ public UserLogoutResponse logout(UserLogoutRequest request, Token token) {
+ UserLogoutResponse response = new UserLogoutResponse();
+ CookieUtil.clearCookie("token");
+ return response;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/action/api/conf/MappingApi.java b/src/main/java/xyz/wbsite/action/api/conf/MappingApi.java
new file mode 100644
index 0000000..ec6c567
--- /dev/null
+++ b/src/main/java/xyz/wbsite/action/api/conf/MappingApi.java
@@ -0,0 +1,33 @@
+package xyz.wbsite.action.api.conf;
+
+import xyz.wbsite.frame.auth.LocalData;
+import xyz.wbsite.module.conf.mgr.MappingManager;
+import xyz.wbsite.module.conf.req.*;
+import xyz.wbsite.module.conf.rsp.*;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class MappingApi{
+
+ @Autowired
+ private MappingManager mappingManager;
+
+ public MappingCreateResponse create(MappingCreateRequest request) {
+ return mappingManager.create(request, LocalData.getToken());
+ }
+
+ public MappingDeleteResponse delete(MappingDeleteRequest request) {
+ return mappingManager.delete(request, LocalData.getToken());
+ }
+
+ public MappingUpdateResponse update(MappingUpdateRequest request) {
+ return mappingManager.update(request, LocalData.getToken());
+ }
+
+ public MappingFindResponse find(MappingFindRequest request) {
+ return mappingManager.find(request, LocalData.getToken());
+ }
+
+ public MappingGetResponse get(MappingGetRequest request) {
+ return mappingManager.get(request, LocalData.getToken());
+ }
+}
diff --git a/src/main/java/xyz/wbsite/action/control/Header.java b/src/main/java/xyz/wbsite/action/control/Header.java
new file mode 100644
index 0000000..c365fb7
--- /dev/null
+++ b/src/main/java/xyz/wbsite/action/control/Header.java
@@ -0,0 +1,15 @@
+package xyz.wbsite.action.control;
+
+import xyz.wbsite.frame.base.Control;
+import org.springframework.ui.Model;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class Header extends Control {
+
+ @Override
+ public void exec(Model model, HttpServletRequest request, HttpServletResponse response) {
+
+ }
+}
diff --git a/src/main/java/xyz/wbsite/action/screen/Index.java b/src/main/java/xyz/wbsite/action/screen/Index.java
new file mode 100644
index 0000000..261e2e5
--- /dev/null
+++ b/src/main/java/xyz/wbsite/action/screen/Index.java
@@ -0,0 +1,22 @@
+package xyz.wbsite.action.screen;
+
+import xyz.wbsite.frame.base.Screen;
+import org.springframework.ui.Model;
+import java.util.HashMap;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class Index extends Screen {
+
+ @Override
+ public void exec(Model model, HttpServletRequest request, HttpServletResponse response) {
+
+ // 获取配置
+ HashMap prop = new HashMap<>();
+ prop.put("open", true);//是否保持一个子菜单展开
+ prop.put("coll", false);//左侧菜单是否收缩
+ prop.put("tran", false);//是否展示动画
+ prop.put("full", false);//是否全屏
+ model.addAttribute("prop", prop);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/config/ActionConfig.java b/src/main/java/xyz/wbsite/config/ActionConfig.java
new file mode 100644
index 0000000..7d2e71e
--- /dev/null
+++ b/src/main/java/xyz/wbsite/config/ActionConfig.java
@@ -0,0 +1,138 @@
+package xyz.wbsite.config;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
+import org.springframework.beans.factory.support.BeanNameGenerator;
+import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.core.type.filter.AssignableTypeFilter;
+import org.springframework.core.type.filter.TypeFilter;
+import xyz.wbsite.frame.base.Control;
+import xyz.wbsite.frame.base.Screen;
+import xyz.wbsite.frame.utils.LogUtil;
+
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 请求处理器配置类,Screen及Control
+ *
+ * 注册扫描Screen处理器 {@link ActionConfig#registryScreen}
+ * 注册扫描Control处理器 {@link ActionConfig#registryControl}
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Configuration
+public class ActionConfig implements BeanDefinitionRegistryPostProcessor {
+
+ public static String SCREEN_PREFIX = "/screen/";
+ public static String CONTROL_PREFIX = "/control/";
+ public static String AJAX_PREFIX = "/ajax/";
+ public static String API_PREFIX = "/api/";
+
+ @Override
+ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
+ String aPackage = this.getClass().getPackage().getName();
+ Pattern compile = Pattern.compile("(.*)\\.config");
+ Matcher matcher = compile.matcher(aPackage);
+ if (matcher.find()) {
+ String basePackage = matcher.group(1);
+ registryScreen(basePackage + ".action.screen", beanDefinitionRegistry);
+ registryControl(basePackage + ".action.control", beanDefinitionRegistry);
+ registryAjax(basePackage + ".action.ajax", beanDefinitionRegistry);
+ registryApi(basePackage + ".action.api", beanDefinitionRegistry);
+ }
+ }
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
+
+ }
+
+ private int registryScreen(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.resetFilters(false);
+ classPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(Screen.class));
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ String beamName = beanClassName.replaceAll(basePackage + ".", SCREEN_PREFIX).replaceAll("\\.","/").toLowerCase();
+ LogUtil.i("registry screen " + beamName);
+ return beamName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+
+ private int registryControl(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.resetFilters(false);
+ classPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(Control.class));
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ String beamName = beanClassName.replaceAll(basePackage + ".", CONTROL_PREFIX).replaceAll("\\.","/").toLowerCase();
+ LogUtil.i("registry control " + beamName);
+ return beamName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+
+ private int registryAjax(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.resetFilters(false);
+ classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
+ @Override
+ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
+ return true;
+ }
+ });
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ if (beanClassName != null && beanClassName.endsWith("Ajax")) {
+ beanClassName = beanClassName.substring(0, beanClassName.length() - 4);
+ }
+ String beamName = beanClassName.replaceAll(basePackage + ".", AJAX_PREFIX).replaceAll("\\.","/").toLowerCase();
+ LogUtil.i("registry ajax " + beamName);
+ return beamName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+
+ private int registryApi(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
+ @Override
+ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
+ return true;
+ }
+ });
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ if (beanClassName != null && beanClassName.endsWith("Api")) {
+ beanClassName = beanClassName.substring(0, beanClassName.length() - 3);
+ }
+ String beamName = beanClassName.replaceAll(basePackage + ".", API_PREFIX).replaceAll("\\.","/").toLowerCase();
+ LogUtil.i("registry api " + beamName);
+ return beamName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/config/CacheConfig.java b/src/main/java/xyz/wbsite/config/CacheConfig.java
new file mode 100644
index 0000000..aed761c
--- /dev/null
+++ b/src/main/java/xyz/wbsite/config/CacheConfig.java
@@ -0,0 +1,45 @@
+package xyz.wbsite.config;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.config.CacheConfiguration;
+import net.sf.ehcache.config.DiskStoreConfiguration;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.ehcache.EhCacheCacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableCaching
+public class CacheConfig {
+
+ public static final String TOKEN_CACHE = "tokenCache";
+
+ @Bean
+ public EhCacheCacheManager getCacheManager() {
+ net.sf.ehcache.config.Configuration configuration = new net.sf.ehcache.config.Configuration();
+ // todo 需根据服务器物理内存配置
+ configuration.setMaxBytesLocalHeap("128M");
+ configuration.updateCheck(false);
+ configuration.addDiskStore(new DiskStoreConfiguration().path("java.io.tmpdir"));
+ CacheManager cacheManager = CacheManager.create(configuration);
+
+ // 添加token缓存
+ cacheManager.addCache(buildTokenCache());
+ return new EhCacheCacheManager(cacheManager);
+ }
+
+ /**
+ * 构建TokenCache
+ *
+ * @return 缓存
+ */
+ private Cache buildTokenCache() {
+ CacheConfiguration config = new CacheConfiguration();
+ config.setMemoryStoreEvictionPolicy("LFU");//最少使用
+ config.setTimeToLiveSeconds(60 * 60);//最长有效时间
+ config.setTimeToIdleSeconds(60 * 60);//无访问最长有效时间
+ config.setName(TOKEN_CACHE);
+ return new Cache(config);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/config/FreeMarkerConfig.java b/src/main/java/xyz/wbsite/config/FreeMarkerConfig.java
new file mode 100644
index 0000000..513c9d5
--- /dev/null
+++ b/src/main/java/xyz/wbsite/config/FreeMarkerConfig.java
@@ -0,0 +1,124 @@
+package xyz.wbsite.config;
+
+import freemarker.template.SimpleScalar;
+import freemarker.template.TemplateMethodModelEx;
+import freemarker.template.TemplateModelException;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.validation.support.BindingAwareModelMap;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
+import xyz.wbsite.frame.auth.LocalData;
+import xyz.wbsite.frame.base.Control;
+import xyz.wbsite.frame.utils.UrlUtil;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.util.List;
+import java.util.Locale;
+
+import static xyz.wbsite.config.ActionConfig.CONTROL_PREFIX;
+import static xyz.wbsite.config.ActionConfig.SCREEN_PREFIX;
+
+@Configuration
+public class FreeMarkerConfig {
+ @Autowired
+ private FreeMarkerViewResolver viewResolver;
+ @Autowired
+ private freemarker.template.Configuration configuration;
+ @Value("${server.servlet.context-path}")
+ private String context;
+
+ private String suffix = ".ftl";
+
+ @PostConstruct
+ public void setSharedVariable() throws TemplateModelException {
+ // 全局共享变量、函数
+ configuration.setSharedVariable("context", context);
+ configuration.setSharedVariable("screenHolder", new ScreenHolder());
+ configuration.setSharedVariable("controlHolder", new ControlHolder());
+ configuration.setSharedVariable("UrlUtil", new UrlUtil());
+ }
+
+ private class ScreenHolder implements TemplateMethodModelEx {
+
+ @Override
+ public Object exec(List list) throws TemplateModelException {
+ try {
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ LocaleResolver localeResolver = (LocaleResolver) request.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE);
+ String servletPath = LocalData.getAction();
+ servletPath = servletPath.replaceAll("^/", "");
+
+ String[] split = servletPath.split("/");
+ StringBuilder sb = new StringBuilder("");
+
+ // 分割组装路径
+ for (int i = 0; i < split.length; i++) {
+ sb.append(split[i]);
+ if (i != split.length - 1) {
+ sb.append(File.separator);
+ }
+ }
+
+ Locale locale = localeResolver.resolveLocale(request);
+ String viewName = "screen" + File.separator + sb.toString();
+ View view = viewResolver.resolveViewName(viewName, locale);
+ //无法找到对应screen
+ if (view == null) {
+ return "";
+ } else {
+ return SCREEN_PREFIX + servletPath + suffix;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ }
+
+ private class ControlHolder implements TemplateMethodModelEx {
+
+ @Override
+ public Object exec(List list) throws TemplateModelException {
+ String control = "";
+ if (list.size() != 1) {
+ return "";
+ }
+ Object o = list.get(0);
+ if (o instanceof SimpleScalar) {
+ control = ((SimpleScalar) o).getAsString();
+ }
+
+ // 查找是否存在对应控制面板执行器
+ Control controlExec = null;
+ try {
+ String beanClassName = (CONTROL_PREFIX + control).toLowerCase();
+ controlExec = LocalData.getApplicationContext().getBean(beanClassName, Control.class);
+
+ HttpServletRequest request = LocalData.getRequest();
+ HttpServletResponse response = LocalData.getResponse();
+
+ BindingAwareModelMap modelMap = new BindingAwareModelMap();
+ controlExec.exec(modelMap, request, response);
+
+ for (String key : modelMap.keySet()) {
+ request.setAttribute(key, modelMap.get(key));
+ }
+ } catch (BeansException e) {
+
+ }
+
+ control = control.replaceAll("/", File.separator);
+ return CONTROL_PREFIX + control + suffix;
+ }
+ }
+}
diff --git a/src/main/java/xyz/wbsite/config/SQLiteConfig.java b/src/main/java/xyz/wbsite/config/SQLiteConfig.java
new file mode 100644
index 0000000..f85b259
--- /dev/null
+++ b/src/main/java/xyz/wbsite/config/SQLiteConfig.java
@@ -0,0 +1,32 @@
+package xyz.wbsite.config;
+
+import xyz.wbsite.frame.utils.ResourceUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Configuration
+public class SQLiteConfig {
+
+ @Value("${spring.datasource.url}")
+ private String url;
+
+ @PostConstruct
+ public void generateDB() {
+ Pattern compile = Pattern.compile("jdbc:sqlite:(.*.db).*");
+ Matcher matcher = compile.matcher(url);
+ if (matcher.find()) {
+ String group = matcher.group(1);
+ File file = new File(group);
+ if (!file.exists()) {
+ File path = file.getAbsoluteFile().getParentFile();
+ if (!path.exists()) path.mkdirs();
+ ResourceUtil.copyResource2File("nginx-admin.db", file);
+ }
+ }
+ }
+}
diff --git a/src/main/java/xyz/wbsite/config/ScheduleConfig.java b/src/main/java/xyz/wbsite/config/ScheduleConfig.java
new file mode 100644
index 0000000..f5c9ed8
--- /dev/null
+++ b/src/main/java/xyz/wbsite/config/ScheduleConfig.java
@@ -0,0 +1,91 @@
+package xyz.wbsite.config;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
+import org.springframework.beans.factory.support.BeanNameGenerator;
+import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.core.type.filter.AssignableTypeFilter;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.stereotype.Component;
+import xyz.wbsite.frame.schedule.RunTask;
+import xyz.wbsite.frame.utils.LogUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 计划调度配置,可以指定环境生效,根据实际情况是否需要开启
+ * 开启方法:将@Profile("dev") 删除(所有环境生效) 或改为对应环境
+ */
+@Configuration
+@Component
+public class ScheduleConfig extends ThreadPoolTaskScheduler implements BeanDefinitionRegistryPostProcessor {
+
+ private Map> classMap;
+
+ private Map> futureMap;
+
+ public ScheduleConfig() {
+ classMap = new HashMap<>();
+ futureMap = new HashMap<>();
+ setPoolSize(4);
+ initialize();
+ }
+
+ public boolean createOrRepeat(RunTask task) {
+ if (futureMap.containsKey(task.taskId())) {
+ ScheduledFuture> scheduledFuture = futureMap.get(task.taskId());
+ scheduledFuture.cancel(false);
+ }
+ classMap.put(task.taskId(), (Class) task.getClass());
+ futureMap.put(task.taskId(), task.schedule(this));
+ return true;
+ }
+
+ @Override
+ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
+ String aPackage = this.getClass().getPackage().getName();
+ Pattern compile = Pattern.compile("(.*)\\.config");
+ Matcher matcher = compile.matcher(aPackage);
+ if (matcher.find()) {
+ String basePackage = matcher.group(1);
+ registryTask(basePackage, beanDefinitionRegistry);
+ }
+ }
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
+
+ }
+
+ private int registryTask(String basePackage, BeanDefinitionRegistry beanDefinitionRegistry) {
+ ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
+ classPathBeanDefinitionScanner.resetFilters(false);
+ classPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(RunTask.class));
+ classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
+ @Override
+ public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
+ String beanClassName = beanDefinition.getBeanClassName();
+ try {
+ Class> aClass = Class.forName(beanClassName);
+ Object instance = aClass.newInstance();
+ RunTask task = (RunTask) instance;
+ ScheduleConfig.this.createOrRepeat(task);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ LogUtil.i("registry task " + beanClassName);
+ return beanClassName;
+ }
+ });
+ return classPathBeanDefinitionScanner.scan(basePackage);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/config/SecurityConfig.java b/src/main/java/xyz/wbsite/config/SecurityConfig.java
new file mode 100644
index 0000000..52be9be
--- /dev/null
+++ b/src/main/java/xyz/wbsite/config/SecurityConfig.java
@@ -0,0 +1,130 @@
+package xyz.wbsite.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;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
+import xyz.wbsite.frame.auth.LocalData;
+import xyz.wbsite.frame.auth.Token;
+import xyz.wbsite.frame.utils.CookieUtil;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+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;
+
+@Configuration
+@EnableGlobalMethodSecurity(securedEnabled = true)
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Value("${web.url.auth.included}")
+ private String[] included;
+ @Value("${web.url.auth.excluded}")
+ private String[] excluded;
+ @Value("${spring.mvc.static-path-pattern}")
+ private String[] staticPath;
+ @Value("${web.login.page}")
+ private String loginPage;
+
+ @Override
+ public void configure(WebSecurity web) throws Exception {
+ web.ignoring().mvcMatchers(staticPath);
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ .and()
+ .addFilterBefore(new TokenFilter(), FilterSecurityInterceptor.class)// 过滤器用于处理Token
+ .authorizeRequests()
+ .antMatchers(excluded).permitAll()// 放行排除的URL
+ .antMatchers(included).access("@Authorization.hasPermission(request,authentication)")// 需要权限的URL
+ .and().cors()
+ .and().headers().frameOptions().disable()
+ .and().csrf().disable();
+ }
+
+ /**
+ * 此方法不要删除 用于屏蔽默认用户密码生成
+ *
+ * 例如 Using generated security password: f6b42a66-71b1-4c31-b6a8-942838c81408
+ *
+ * @return
+ * @throws Exception
+ */
+ @Bean
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ public static class TokenFilter implements Filter {
+
+ @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");
+ }
+
+ // 组装Token ~ 这边根据实际的业务组装Token
+ if (token != null) {
+ LocalData.setToken( LocalData.getSysToken());
+ } else {
+ LocalData.setToken(null);
+ }
+
+ // Action
+ String servletPath = request.getServletPath().toLowerCase();
+ Pattern compile = Pattern.compile("^/(.+)\\.htm");
+ Matcher matcher = compile.matcher(servletPath);
+ if (matcher.find()) {
+ LocalData.setAction(matcher.group(1));
+ }
+
+ try {
+ filterChain.doFilter(servletRequest, servletResponse);
+ } catch (AccessDeniedException e) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ } catch (Exception e) {
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+ }
+
+ @Bean("Authorization")
+ public Object getAuthorization() {
+ return new Object() {
+ public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
+
+ Token token_ = LocalData.getToken();
+ if (token_ == null) {
+ return false;
+ }
+
+ String path = request.getServletPath();
+ if (token_.hasRes(path)) {
+ return true;
+ }
+
+ return false;
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/xyz/wbsite/config/ThreadPoolConfig.java b/src/main/java/xyz/wbsite/config/ThreadPoolConfig.java
new file mode 100644
index 0000000..354e761
--- /dev/null
+++ b/src/main/java/xyz/wbsite/config/ThreadPoolConfig.java
@@ -0,0 +1,56 @@
+package xyz.wbsite.config;
+
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.lang.Nullable;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+@EnableAsync
+public class ThreadPoolConfig implements AsyncConfigurer {
+ private ThreadPoolTaskExecutor executor;
+
+ private int corePoolSize = 10;//线程池维护线程的最少数量
+
+ private int maxPoolSize = 30;//线程池维护线程的最大数量
+
+ private int queueCapacity = 8; //缓存队列
+
+ private int keepAlive = 60;//允许的空闲时间
+
+ @Nullable
+ @Override
+ public Executor getAsyncExecutor() {
+ executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(corePoolSize);
+ executor.setMaxPoolSize(maxPoolSize);
+ executor.setQueueCapacity(queueCapacity);
+ executor.setThreadNamePrefix("mqExecutor-");
+ // rejection-policy:当pool已经达到max size的时候,如何处理新任务
+ // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //对拒绝task的处理策略
+ executor.setKeepAliveSeconds(keepAlive);
+ executor.initialize();
+ return executor;
+ }
+
+
+ @Nullable
+ @Override
+ public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+ return new AsyncUncaughtExceptionHandler() {
+
+ @Override
+ public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
+ System.out.println("-------------》》》捕获线程异常信息");
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/xyz/wbsite/config/WebMvcConfig.java b/src/main/java/xyz/wbsite/config/WebMvcConfig.java
new file mode 100644
index 0000000..6c023a8
--- /dev/null
+++ b/src/main/java/xyz/wbsite/config/WebMvcConfig.java
@@ -0,0 +1,122 @@
+package xyz.wbsite.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+import xyz.wbsite.frame.utils.LogUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+ @Value("${web.home.page}")
+ private String homePage;
+ @Value("${spring.mvc.static-path-pattern}")
+ private String[] staticPath;
+
+ /**
+ * 增加全局拦截器,可用于异常日志的收集
+ *
+ * @param registry
+ */
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ // 全局异常收集拦截器
+ registry.addInterceptor(new HandlerInterceptorAdapter() {
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+ super.afterCompletion(request, response, handler, ex);
+
+ if (ex != null) {
+ LogUtil.dumpException(ex);
+ }
+ }
+
+ }).addPathPatterns("/**").excludePathPatterns(staticPath);
+ }
+
+ /**
+ * Jackson序列化时的转化规则配置
+ *
+ * 1、Long或long类型在序列化时转String,防止出现javascript中Number精度丢失的情况。
+ *
+ * @param converters
+ */
+ @Override
+ public void extendMessageConverters(List> converters) {
+ for (HttpMessageConverter> converter : converters) {
+ if (converter instanceof MappingJackson2HttpMessageConverter) {
+ ObjectMapper objectMapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
+ SimpleModule simpleModule = new SimpleModule();
+ simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
+ simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
+ objectMapper.registerModule(simpleModule);
+ }
+ }
+ }
+
+// @Bean
+// @Profile("prod")
+// public ServletWebServerFactory servletContainer() {
+// TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
+//
+// // 基本参数
+// String keyStore = "1754557_www.wbsite.xyz.pfx";
+// String keyStorePassword = "s98n7CLd";
+// String keyStoreType = "PKCS12";
+// int httpsPort = 443;
+//
+// File keystore = null;
+// // 正常开发可以通过getFile()获取,打包jar后无法直接获取File对象,需将文件考出
+// try {
+// keystore = new ClassPathResource(keyStore).getFile();
+// } catch (IOException ex) {
+// try {
+// ApplicationHome home = new ApplicationHome(getClass());
+// // 当前运行jar文件
+// File jarFile = home.getSource();
+// //jar同目录
+// keystore = new File(jarFile.getParent(), keyStore);
+//
+// InputStream inputStream = new ClassPathResource(keyStore).getInputStream();
+// byte[] bytes = new byte[inputStream.available()];
+//
+// inputStream.read(bytes);
+//
+// inputStream.close();
+//
+// FileOutputStream fileOutputStream = new FileOutputStream(keystore);
+// fileOutputStream.write(bytes);
+// fileOutputStream.close();
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// }
+//
+// // 创建Connector
+// Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
+// Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
+// connector.setScheme("https");
+// connector.setSecure(true);
+// connector.setPort(httpsPort);
+// protocol.setSSLEnabled(true);
+// protocol.setKeystoreFile(keystore.getAbsolutePath());
+// protocol.setKeystorePass(keyStorePassword);
+// protocol.setKeystoreType(keyStoreType);
+//
+// // 添加
+// tomcat.addAdditionalTomcatConnectors(connector);
+// return tomcat;
+// }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/frame/auth/LocalData.java b/src/main/java/xyz/wbsite/frame/auth/LocalData.java
new file mode 100644
index 0000000..cd6f41b
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/auth/LocalData.java
@@ -0,0 +1,95 @@
+package xyz.wbsite.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 xyz.wbsite.frame.auth.Token;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * LocalData - 本地数据存放类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class LocalData {
+
+ private static ApplicationContext applicationContext = null;
+
+ private static Token system = null;
+
+ static {
+ // 组装系统Token
+ system = new Token();
+ system.setId(0);
+ system.setUserId(0);
+ system.setUserName("system");
+ system.putRes(".*");
+ }
+
+ public static Token getSysToken() {
+ return system;
+ }
+
+ /**
+ * 当请求目标 target = '/aa/bb'
+ */
+ private static final ThreadLocal actionHolder = new ThreadLocal();
+
+ public static String getAction() {
+ return actionHolder.get();
+ }
+
+ public static void setAction(String action) {
+ actionHolder.set(action);
+ }
+
+ /**
+ * 当前用户的通行证
+ */
+ private static final ThreadLocal tokenHolder = new ThreadLocal();
+
+ public static Token getToken() {
+ return tokenHolder.get();
+ }
+
+ public static void setToken(Token token) {
+ tokenHolder.set(token);
+ }
+
+ public static HttpServletRequest getRequest() {
+ return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ }
+
+ public static HttpServletResponse getResponse() {
+ return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
+ }
+
+ public static ApplicationContext getApplicationContext() {
+ return LocalData.applicationContext;
+ }
+
+ public static void setApplicationContext(ApplicationContext applicationContext) {
+ LocalData.applicationContext = applicationContext;
+ }
+
+ public static T getBean(Class t) {
+ if (getApplicationContext() == null) {
+ return null;
+ }
+ try {
+ return getApplicationContext().getBean(t);
+ } catch (BeansException ignored) {
+ return null;
+ }
+ }
+
+ public static Environment getEnvironment() {
+ return getBean(Environment.class);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/auth/Token.java b/src/main/java/xyz/wbsite/frame/auth/Token.java
new file mode 100644
index 0000000..ac4274f
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/auth/Token.java
@@ -0,0 +1,91 @@
+package xyz.wbsite.frame.auth;
+
+import xyz.wbsite.frame.utils.IDgenerator;
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Token - 通行证类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class Token implements Serializable {
+ private static final Long serialVersionUID = 1L;
+ /**
+ * ID
+ */
+ private long id;
+ /**
+ * TOKEN
+ */
+ private String token;
+ /**
+ * 用户ID
+ */
+ private long userId;
+ /**
+ * 用户名称
+ */
+ private String userName;
+
+ private Set resSet = new HashSet<>();
+
+ public boolean hasRes(String res) {
+ for (String s : resSet) {
+ if (res.matches(s)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void putRes(String resource) {
+ resSet.add(resource);
+ }
+
+ public void putRes(Set resourceSet) {
+ this.resSet.addAll(resourceSet);
+ }
+
+
+ public Set getResSet() {
+ return resSet;
+ }
+
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(long userId) {
+ this.userId = userId;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/BaseEntity.java b/src/main/java/xyz/wbsite/frame/base/BaseEntity.java
new file mode 100644
index 0000000..2bdb6f1
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/BaseEntity.java
@@ -0,0 +1,110 @@
+package xyz.wbsite.frame.base;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * Base - 基类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class BaseEntity implements Serializable {
+
+ /**
+ * 主键
+ */
+ private long id;
+
+ /**
+ * 行版本
+ */
+ private long rowVersion;
+
+ /**
+ * 创建用户
+ */
+ @JsonIgnore
+ private long createBy;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+ /**
+ * 最后更新用户
+ */
+ @JsonIgnore
+ private long lastUpdateBy;
+
+ /**
+ * 最后更新时间
+ */
+ @JsonIgnore
+ private Date lastUpdateTime;
+
+ /**
+ * 是否删除
+ */
+ @JsonIgnore
+ private boolean isDeleted;
+
+ public long getRowVersion() {
+ return rowVersion;
+ }
+
+ public void setRowVersion(long rowVersion) {
+ this.rowVersion = rowVersion;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public long getCreateBy() {
+ return createBy;
+ }
+
+ public void setCreateBy(long createBy) {
+ this.createBy = createBy;
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ public long getLastUpdateBy() {
+ return lastUpdateBy;
+ }
+
+ public void setLastUpdateBy(long lastUpdateBy) {
+ this.lastUpdateBy = lastUpdateBy;
+ }
+
+ public Date getLastUpdateTime() {
+ return lastUpdateTime;
+ }
+
+ public void setLastUpdateTime(Date lastUpdateTime) {
+ this.lastUpdateTime = lastUpdateTime;
+ }
+
+ public boolean getIsDeleted() {
+ return isDeleted;
+ }
+
+ public void setIsDeleted(boolean deleted) {
+ isDeleted = deleted;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/BaseFindRequest.java b/src/main/java/xyz/wbsite/frame/base/BaseFindRequest.java
new file mode 100644
index 0000000..448fbe6
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/BaseFindRequest.java
@@ -0,0 +1,52 @@
+package xyz.wbsite.frame.base;
+
+/**
+ * BaseFindRequest - 基类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @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() {
+ return pageNumber;
+ }
+
+ public void setPageNumber(int pageNumber) {
+ this.pageNumber = pageNumber;
+ }
+
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ public void setPageSize(int pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ public String getSortKey() {
+ return sortKey;
+ }
+
+ public void setSortKey(String sortKey) {
+ this.sortKey = sortKey;
+ }
+
+ public SortType getSortType() {
+ return sortType;
+ }
+
+ public void setSortType(SortType sortType) {
+ this.sortType = sortType;
+ }
+
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/BaseFindResponse.java b/src/main/java/xyz/wbsite/frame/base/BaseFindResponse.java
new file mode 100644
index 0000000..d351c2e
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/BaseFindResponse.java
@@ -0,0 +1,33 @@
+package xyz.wbsite.frame.base;
+
+import java.util.List;
+
+/**
+ * BaseFindResponse - 基类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class BaseFindResponse extends BaseResponse{
+
+ private List result;
+
+ private Long totalCount;
+
+ public List getResult() {
+ return result;
+ }
+
+ public void setResult(List result) {
+ this.result = result;
+ }
+
+ public Long getTotalCount() {
+ return totalCount;
+ }
+
+ public void setTotalCount(Long totalCount) {
+ this.totalCount = totalCount;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/BaseRequest.java b/src/main/java/xyz/wbsite/frame/base/BaseRequest.java
new file mode 100644
index 0000000..a24b7c9
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/BaseRequest.java
@@ -0,0 +1,12 @@
+package xyz.wbsite.frame.base;
+
+/**
+ * BaseRequest - 基类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class BaseRequest {
+
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/BaseResponse.java b/src/main/java/xyz/wbsite/frame/base/BaseResponse.java
new file mode 100644
index 0000000..8766d33
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/BaseResponse.java
@@ -0,0 +1,38 @@
+package xyz.wbsite.frame.base;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * BaseResponse - 基类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class BaseResponse {
+ private List errors = new ArrayList();
+
+ public void addError(Error error){
+ this.errors.add(error);
+ }
+
+ public void addError(ErrorType type,String message){
+ this.errors.add(new Error(type,message));
+ }
+
+ public void addErrors(List errors){
+ this.errors.addAll(errors);
+ }
+
+ public boolean hasError(){
+ return this.errors.size() > 0;
+ }
+
+ /**
+ * 获取全部的错误信息,返回的是副本
+ */
+ public List getErrors() {
+ return new ArrayList(errors);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/BaseSearchRequest.java b/src/main/java/xyz/wbsite/frame/base/BaseSearchRequest.java
new file mode 100644
index 0000000..62cd20f
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/BaseSearchRequest.java
@@ -0,0 +1,24 @@
+package xyz.wbsite.frame.base;
+
+/**
+ * BaseSearchRequest - 基类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class BaseSearchRequest extends BaseFindRequest {
+
+ /**
+ * 模糊查询的关键字。
+ */
+ private String keyword;
+
+ public String getKeyword() {
+ return keyword;
+ }
+
+ public void setKeyword(String keyword) {
+ this.keyword = keyword;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/BaseUpdateRequest.java b/src/main/java/xyz/wbsite/frame/base/BaseUpdateRequest.java
new file mode 100644
index 0000000..9a8578d
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/BaseUpdateRequest.java
@@ -0,0 +1,24 @@
+package xyz.wbsite.frame.base;
+
+/**
+ * BaseUpdateRequest - 基类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class BaseUpdateRequest extends BaseRequest{
+
+ /**
+ * 版本戳
+ */
+ private long rowVersion;
+
+ public long getRowVersion() {
+ return rowVersion;
+ }
+
+ public void setRowVersion(long rowVersion) {
+ this.rowVersion = rowVersion;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/frame/base/Control.java b/src/main/java/xyz/wbsite/frame/base/Control.java
new file mode 100644
index 0000000..1074730
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/Control.java
@@ -0,0 +1,10 @@
+package xyz.wbsite.frame.base;
+
+import org.springframework.ui.Model;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public abstract class Control {
+ public abstract void exec(Model model, HttpServletRequest request, HttpServletResponse response);
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/frame/base/Error.java b/src/main/java/xyz/wbsite/frame/base/Error.java
new file mode 100644
index 0000000..72cc105
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/Error.java
@@ -0,0 +1,41 @@
+package xyz.wbsite.frame.base;
+
+/**
+ * Error - 错误基类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class Error {
+
+ /*错误类型*/
+ private ErrorType type;
+
+ /*错误内容*/
+ private String message;
+
+ public Error() {
+ }
+
+ public Error(ErrorType type, String message) {
+ this.type = type;
+ this.message = message;
+ }
+
+ public ErrorType getType() {
+ return type;
+ }
+
+ public void setType(ErrorType type) {
+ this.type = type;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/ErrorType.java b/src/main/java/xyz/wbsite/frame/base/ErrorType.java
new file mode 100644
index 0000000..17fb52c
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/ErrorType.java
@@ -0,0 +1,17 @@
+package xyz.wbsite.frame.base;
+
+/**
+ * ErrorType - 错误类型
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public enum ErrorType {
+ BUSINESS_ERROR,
+ SYSTEM_ERROR,
+ UNKNOWN_ERROR,
+ UNIQUENESS_ERROR,
+ EXPECTATION_NULL,
+ INVALID_PARAMETER
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/Screen.java b/src/main/java/xyz/wbsite/frame/base/Screen.java
new file mode 100644
index 0000000..c2c66ed
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/Screen.java
@@ -0,0 +1,10 @@
+package xyz.wbsite.frame.base;
+
+import org.springframework.ui.Model;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public abstract class Screen {
+ public abstract void exec(Model model, HttpServletRequest request, HttpServletResponse response);
+}
diff --git a/src/main/java/xyz/wbsite/frame/base/SortType.java b/src/main/java/xyz/wbsite/frame/base/SortType.java
new file mode 100644
index 0000000..3351d9d
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/base/SortType.java
@@ -0,0 +1,17 @@
+package xyz.wbsite.frame.base;
+
+/**
+ * SortTypeEnum - 排序方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public enum SortType {
+
+ //升序
+ ASC,
+
+ //降序
+ DESC
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/frame/excel/WCell.java b/src/main/java/xyz/wbsite/frame/excel/WCell.java
new file mode 100644
index 0000000..a1cc37b
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/WCell.java
@@ -0,0 +1,47 @@
+package xyz.wbsite.frame.excel;
+
+import java.io.Serializable;
+
+/**
+ * WCell - Excel单元格对象
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class WCell implements Serializable {
+
+ /**
+ * 单元格的值,任意格式都将转化为字符类型
+ */
+ private String value;
+
+ /**
+ * 单元格存在的错误,只在excel导入时会产生错误
+ */
+ private String error;
+
+ public WCell() {
+ this.value = "";
+ }
+
+ public WCell(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public void setError(String error) {
+ this.error = error;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/WColumn.java b/src/main/java/xyz/wbsite/frame/excel/WColumn.java
new file mode 100644
index 0000000..0fbcb2f
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/WColumn.java
@@ -0,0 +1,146 @@
+package xyz.wbsite.frame.excel;
+
+
+import xyz.wbsite.frame.excel.converter.Converter;
+
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * WColumn - Excel列对象(包含列名,长度,必须项,列描述,指定转换器)
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class WColumn implements Serializable {
+ /**
+ * 列名
+ */
+ private String name = "";
+ /**
+ * 列宽度
+ */
+ private int cellWidth = 8;
+ /**
+ * 是否是必输列
+ */
+ private boolean isRequired = false;
+ /**
+ * 该列的描述字段
+ */
+ private String description = "";
+ /**
+ * 列转换器
+ */
+ private Converter converter;
+ /**
+ * Field对象
+ */
+ private Field field;
+ /**
+ * set方法
+ */
+ private Method setMethod;
+ /**
+ * get方法
+ */
+ private Method getMethod;
+ /**
+ * ExcelType
+ */
+ private int cellType = 1;
+ /**
+ * 下拉列表
+ */
+ private String[] cellList;
+
+ public WColumn() {
+ this.name = "";
+ }
+
+ public WColumn(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Field getField() {
+ return field;
+ }
+
+ public void setField(Field field) {
+ this.field = field;
+ }
+
+ public int getCellWidth() {
+ return cellWidth;
+ }
+
+ public void setCellWidth(int cellWidth) {
+ this.cellWidth = cellWidth;
+ }
+
+ public boolean isRequired() {
+ return isRequired;
+ }
+
+ public void setRequired(boolean isRequired) {
+ this.isRequired = isRequired;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Converter getConverter() {
+ return converter;
+ }
+
+ public void setConverter(Converter converter) {
+ this.converter = converter;
+ }
+
+ public int getCellType() {
+ return cellType;
+ }
+
+ public void setCellType(int cellType) {
+ this.cellType = cellType;
+ }
+
+ public Method getSetMethod() {
+ return setMethod;
+ }
+
+ public void setSetMethod(Method setMethod) {
+ this.setMethod = setMethod;
+ }
+
+ public Method getGetMethod() {
+ return getMethod;
+ }
+
+ public void setGetMethod(Method getMethod) {
+ this.getMethod = getMethod;
+ }
+
+ public String[] getCellList() {
+ return cellList;
+ }
+
+ public void setCellList(String[] cellList) {
+ this.cellList = cellList;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/WExcel.java b/src/main/java/xyz/wbsite/frame/excel/WExcel.java
new file mode 100644
index 0000000..0032f59
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/WExcel.java
@@ -0,0 +1,681 @@
+package xyz.wbsite.frame.excel;
+
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFComment;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.ss.util.NumberToTextConverter;
+import xyz.wbsite.frame.excel.annotation.ColumnDescription;
+import xyz.wbsite.frame.excel.annotation.ColumnList;
+import xyz.wbsite.frame.excel.annotation.ColumnName;
+import xyz.wbsite.frame.excel.annotation.Convert;
+import xyz.wbsite.frame.excel.annotation.Ignore;
+import xyz.wbsite.frame.excel.annotation.ParentFirst;
+import xyz.wbsite.frame.excel.annotation.SheetName;
+import xyz.wbsite.frame.excel.converter.BooleanConverter;
+import xyz.wbsite.frame.excel.converter.ByteConverter;
+import xyz.wbsite.frame.excel.converter.CharacterConverter;
+import xyz.wbsite.frame.excel.converter.Converter;
+import xyz.wbsite.frame.excel.converter.DateConverter;
+import xyz.wbsite.frame.excel.converter.DoubleConverter;
+import xyz.wbsite.frame.excel.converter.FloatConverter;
+import xyz.wbsite.frame.excel.converter.IntegerConverter;
+import xyz.wbsite.frame.excel.converter.LongConverter;
+import xyz.wbsite.frame.excel.converter.ShortConverter;
+import xyz.wbsite.frame.excel.converter.StringConverter;
+import xyz.wbsite.frame.excel.exception.ReadErrorException;
+import xyz.wbsite.frame.excel.exception.TemplateNotMatchException;
+import xyz.wbsite.frame.excel.exception.ValueConverterException;
+import xyz.wbsite.frame.excel.style.DataCellStyle;
+import xyz.wbsite.frame.excel.style.ErrorCellStyle;
+import xyz.wbsite.frame.excel.style.HeadCellStyle;
+import xyz.wbsite.frame.excel.style.RedFont;
+import xyz.wbsite.frame.excel.style.SuccessCellStyle;
+import xyz.wbsite.frame.utils.ClassUtil;
+import xyz.wbsite.frame.utils.FileUtil;
+import xyz.wbsite.frame.utils.LogUtil;
+import xyz.wbsite.frame.utils.ValidationUtil;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * WExcel - 抽象的Excel对象数据集合
+ *
+ * 导出
+ * new WExcel(Dept.class).loadData(depts).toFile(file);
+ *
+ * 导入
+ * byte[] bytes = FileUtil.readFileToByteArray(new File("E:\\E.xlsx"));
+ * WExcel check = new WExcel(Dept.class).loadData(bytes);
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class WExcel implements Serializable, Cloneable {
+
+ /**
+ * 表名
+ */
+ private String name;
+
+ /**
+ * 是否冻结第一行
+ */
+ private boolean freezeFirst;
+
+ /**
+ * 模板类
+ */
+ private Class templateClass;
+
+ /**
+ * 表头的集合
+ */
+ private List columnList = new ArrayList<>();
+
+ /**
+ * 单元格里存放的对象
+ */
+ private List rowList = new ArrayList<>();
+
+ /**
+ * 根据输入的模板类打印下载模板。
+ */
+ public WExcel(Class tClass) {
+ this.templateClass = tClass;
+ initColumns(tClass);
+ }
+
+ /**
+ * 根据模板类对DataTable添加相应的列。
+ *
+ * @return WColumn集合
+ */
+ private List initColumns(Class> clazz) {
+ //获取工作簿名称,没有则以类名为默认工作簿名称
+ if (clazz.isAnnotationPresent(SheetName.class)) {
+ SheetName sheetName = clazz.getAnnotation(SheetName.class);
+ this.setName(sheetName.value());
+ this.setFreezeFirst(sheetName.freezeFirst());
+ } else {
+ this.setName(clazz.getSimpleName());
+ }
+
+ //是否关注父类属性
+ boolean parentFirst = clazz.isAnnotationPresent(ParentFirst.class) && clazz.getAnnotation(ParentFirst.class).value();
+ Field[] fields = ClassUtil.getFields(clazz, parentFirst);
+ for (Field field : fields) {
+ if (field.isAnnotationPresent(Ignore.class) && field.getAnnotation(Ignore.class).value()) {
+ continue;
+ }
+
+ WColumn WColumn = new WColumn();
+ WColumn.setField(field);
+
+ Method set = ClassUtil.setMethod(field.getName(), clazz, field.getType());
+ WColumn.setSetMethod(set);
+
+ Method get = ClassUtil.getMethod(field.getName(), clazz);
+ WColumn.setGetMethod(get);
+
+ //获取列名称
+ if (!field.isAnnotationPresent(ColumnName.class)) {
+ WColumn.setName(field.getName());
+ } else {
+ ColumnName columnColumnName = field.getAnnotation(ColumnName.class);
+ WColumn.setName(columnColumnName.value());
+ WColumn.setCellWidth(columnColumnName.width());
+ WColumn.setRequired(columnColumnName.required());
+ }
+ //获取列填写说明或描述
+ if (field.isAnnotationPresent(ColumnDescription.class)) {
+ WColumn.setDescription(field.getAnnotation(ColumnDescription.class).value());
+ }
+ //获取下拉列表
+ if (field.isAnnotationPresent(ColumnList.class)) {
+ WColumn.setCellList(field.getAnnotation(ColumnList.class).value());
+ }
+
+ //获取列类型
+ if (field.isAnnotationPresent(Convert.class)) {
+ Convert converter = field.getAnnotation(Convert.class);
+ Class target = converter.target();
+ try {
+ WColumn.setConverter((Converter) target.newInstance());
+ } catch (InstantiationException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ } else {
+ if (field.getType() == boolean.class || field.getType() == Boolean.class) {
+ WColumn.setConverter(new BooleanConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_BOOLEAN);
+ } else if (field.getType() == byte.class || field.getType() == Byte.class) {
+ WColumn.setConverter(new ByteConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_NUMERIC);
+ } else if (field.getType() == char.class || field.getType() == Character.class) {
+ WColumn.setConverter(new CharacterConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_STRING);
+ } else if (field.getType() == short.class || field.getType() == Short.class) {
+ WColumn.setConverter(new ShortConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_NUMERIC);
+ } else if (field.getType() == int.class || field.getType() == Integer.class) {
+ WColumn.setConverter(new IntegerConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_NUMERIC);
+ } else if (field.getType() == long.class || field.getType() == Long.class) {
+ WColumn.setConverter(new LongConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_NUMERIC);
+ } else if (field.getType() == float.class || field.getType() == Float.class) {
+ WColumn.setConverter(new FloatConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_NUMERIC);
+ } else if (field.getType() == double.class || field.getType() == Double.class) {
+ WColumn.setConverter(new DoubleConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_NUMERIC);
+ } else if (field.getType() == Date.class) {
+ WColumn.setConverter(new DateConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_NUMERIC);
+ } else if (field.getType() == String.class) {
+ WColumn.setConverter(new StringConverter());
+ WColumn.setCellType(Cell.CELL_TYPE_STRING);
+ } else {
+ throw new RuntimeException("Can not find Converter");
+ }
+ }
+
+ columnList.add(WColumn);
+ }
+ return columnList;
+ }
+
+ public WExcel loadData(List list) {
+ return loadData(list, null);
+ }
+
+ /**
+ * 此构造方法仅用于转换对象列表。
+ * 并不会对数据的格式和合法性进行检验。
+ *
+ * @param list 需要导出的对象列表
+ */
+ public WExcel loadData(List list, Processor processor) {
+ if (list.size() > 0) {
+ for (T t : list) {
+ WRow row = new WRow();
+ for (WColumn column : columnList) {
+ if (column == null) {
+ continue;
+ }
+ Method method = column.getGetMethod();
+ try {
+ Object value = method.invoke(t);
+ if (null == value) {
+ row.put(column.getName(), new WCell());
+ } else {
+ String string = column.getConverter().string(value);
+ row.put(column.getName(), new WCell(string));
+ }
+ } catch (IllegalAccessException e) {
+ LogUtil.w("can not invoke get method!");
+ } catch (InvocationTargetException e) {
+ LogUtil.w(method.getName() + " unexpected exception!");
+ }
+ // <2层检查>检查模板注解验证是否通过
+ row.addErrors(ValidationUtil.validate(t));
+ // <3层检查>如果没有错误,则可以执行处理器进行业务处理
+ if (!row.hasError() && processor != null) {
+ List exec = processor.exec(t);
+ row.addErrors(exec != null ? exec : Collections.EMPTY_LIST);
+ }
+ }
+ this.rowList.add(row);
+ }
+ }
+ return this;
+ }
+
+ public WExcel loadData(File file) throws TemplateNotMatchException, ReadErrorException, IOException {
+ return loadData(FileUtil.readFileToByteArray(file), null);
+ }
+
+ public WExcel loadData(File file, Processor processor) throws TemplateNotMatchException, ReadErrorException, IOException {
+ return loadData(FileUtil.readFileToByteArray(file), processor);
+ }
+
+ public WExcel loadData(byte[] bytes) throws TemplateNotMatchException, ReadErrorException {
+ return loadData(bytes, null);
+ }
+
+ /**
+ * 以Excel文件的字节数组为数据源,为自己赋值的同时,与指定的模板类进行数据校验。
+ * 如果匹配过程中发现了不符合的数据,会在对应的单元中添加错误信息。
+ */
+ public WExcel loadData(byte[] bytes, Processor processor) throws TemplateNotMatchException, ReadErrorException {
+ Workbook workbook = null;
+ InputStream is = null;
+ boolean flag;
+ try {
+ flag = true;
+ is = new ByteArrayInputStream(bytes); //读取文件流
+ workbook = new HSSFWorkbook(is);
+ } catch (Exception e) {
+ flag = false;
+ }
+ if (!flag) {
+ try {
+ flag = true;
+ is = new ByteArrayInputStream(bytes); //读取文件流
+ workbook = new XSSFWorkbook(is);
+ } catch (Exception e) {
+ flag = false;
+ }
+ }
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (!flag) {
+ throw new ReadErrorException("读取Excel文件错误");
+ }
+ //第一张Sheet表
+ Sheet sheet = workbook.getSheetAt(0);
+ //获取Sheet名称
+ if (templateClass.isAnnotationPresent(SheetName.class)) {//如果模板存在注解则使用注解名称
+ SheetName sheetName = templateClass.getAnnotation(SheetName.class);
+ this.setName(sheetName.value());
+ } else {//将类名设为表名,如果类名不存在,将Excel表名设为表名
+ this.setName(sheet.getSheetName());
+ }
+
+ //读取表头
+ Row headRow = sheet.getRow(0);
+ //获取Excel列的总数
+ int columnSum = headRow.getPhysicalNumberOfCells();
+
+ //检查列数量
+ if (columnList.size() != columnSum) {
+ throw new TemplateNotMatchException("与模板列数量不同。");
+ } else {
+ for (int i = 0; i < columnList.size(); i++) {
+ WColumn wColumn = columnList.get(i);
+ Cell cell = headRow.getCell(i);
+ String headValue = getValue(cell);
+ headValue = headValue.replace("*", "");
+ headValue = headValue.replace(" ", "");
+
+ if (!wColumn.getName().equals(headValue)) {
+ throw new TemplateNotMatchException("第" + (i + 1) + "项,不匹配的列名," + wColumn.getName() + "和" + headValue);
+ }
+ }
+ }
+
+ //Excel文件的总行数
+ int maxRowNumber = sheet.getLastRowNum();
+ // 逐行读取导入文件的数据
+ for (int i = 0; i < maxRowNumber; i++) {
+ //Excel中的一行数据,第0行为表头,所以要加1
+ Row inputRow = sheet.getRow(i + 1);
+ WRow row = new WRow();
+ rowList.add(row);
+
+ if (null != inputRow) {
+ for (int j = 0; j < columnList.size(); j++) {
+ WColumn wcolumn = columnList.get(j);
+
+ /* 取得当前格子的值 */
+ Cell excelCell = inputRow.getCell(j);
+ WCell WCell = new WCell();
+ row.put(wcolumn.getName(), WCell);
+
+ String value = "";
+ if (null != excelCell) {
+ value = getValue(excelCell);
+ }
+ value = value.trim();
+
+ WCell.setValue(value);
+ }
+ }
+
+ try {
+ T t = templateClass.newInstance();
+ // <1层检查>检查数据格式是否正确
+ row.addErrors(transferMap(row, t));
+ // <2层检查>检查模板注解验证是否通过
+ row.addErrors(ValidationUtil.validate(t));
+ // <3层检查>如果没有错误,则可以执行处理器进行业务处理
+ if (!row.hasError() && processor != null) {
+ List exec = processor.exec(t);
+ row.addErrors(exec != null ? exec : Collections.EMPTY_LIST);
+ }
+ } catch (InstantiationException | IllegalAccessException e) {
+ row.addError("模板对象默认构造函数错误");
+ }
+ }
+ return this;
+ }
+
+ /**
+ * 转换某行为一个对象
+ *
+ * @param row 行对象
+ * @param target 模板对象
+ * @return 模板对象
+ */
+ public List transferMap(WRow row, T target) {
+ List err = new ArrayList<>();
+ for (String key : row.keySet()) {
+ for (WColumn column : columnList) {
+ String name = column.getName();
+ Method setMethod = column.getSetMethod();
+
+ if (key.equals(name)) {
+ WCell WCell = row.get(column.getName());
+ if (null != WCell) {
+ String value = WCell.getValue();
+ //获取转换器
+ Converter converter = column.getConverter();
+ try {
+ setMethod.invoke(target, converter.convert(value));
+ } catch (ValueConverterException e) {
+ e.printStackTrace();
+ err.add(e.getMessage());
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ err.add("[" + setMethod.getName() + "]执行错误");
+ }
+ }
+ break;
+ }
+ }
+ }
+ return err;
+ }
+
+ /**
+ * 获取表名
+ *
+ * @return 表名
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * 设置表名
+ *
+ * @param name 表名
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean getFreezeFirst() {
+ return freezeFirst;
+ }
+
+ public void setFreezeFirst(boolean freezeFirst) {
+ this.freezeFirst = freezeFirst;
+ }
+
+ public final String toCSV() {
+ StringBuilder sb = new StringBuilder();
+
+ for (WColumn WColumn : this.columnList) {
+ if (WColumn != null) {
+ sb.append(WColumn.getName()).append(",");
+ }
+ }
+ sb.append("\n");
+
+ for (int i = 0; i < this.rowList.size(); i++) {
+ for (int j = 0; j < this.columnList.size(); j++) {
+ WColumn wColumn = this.columnList.get(j);
+ WCell wCell = this.rowList.get(i).get(wColumn.getName());
+ sb.append(wCell.getValue()).append(",");
+ }
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * 判断DataTable是否包含错误信息
+ *
+ * @return 是否包含错误.
+ */
+ public final boolean hasError() {
+ for (WRow wRow : rowList) {
+ if (wRow.hasError()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public byte[] getBytes() {
+ XSSFWorkbook workbook = getExcel();
+ if (workbook != null) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ try {
+ workbook.write(outputStream);
+ } catch (IOException e) {
+ return null;
+ }
+ return outputStream.toByteArray();
+ }
+ return null;
+ }
+
+ public XSSFWorkbook getExcel() {
+ XSSFWorkbook workbook = new XSSFWorkbook();
+ //创建一个Sheet表
+ XSSFSheet sheet = workbook.createSheet(name);
+ sheet.setDefaultRowHeightInPoints(18);
+ Row firstRow = sheet.createRow(0); // 下标为0的行开始
+ XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+ int offset = 0;
+ // 添加结果和错误说明列
+ if (hasError()) {
+ offset++;
+ {// 第一栏结果栏
+ Cell firstCell = firstRow.createCell(0);
+ firstCell.setCellStyle(new HeadCellStyle(workbook).getStyle());
+ firstCell.setCellValue(new XSSFRichTextString("执行结果"));
+ XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);
+ XSSFComment comment = drawing.createCellComment(anchor);
+ comment.setString("此列为检查结果,导入时请处理完错误,并删除该列!");
+ firstCell.setCellComment(comment);
+ }
+ offset++;
+ {// 第二栏错误信息栏
+ Cell secondCell = firstRow.createCell(1);
+ secondCell.setCellStyle(new HeadCellStyle(workbook).getStyle());
+ secondCell.setCellValue(new XSSFRichTextString("结果说明"));
+ sheet.setColumnWidth(1, 18 * 256);
+ XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);
+ XSSFComment comment = drawing.createCellComment(anchor);
+ comment.setString("此列为检查结果信息列,导入时请处理完错误,并删除该列!");
+ secondCell.setCellComment(comment);
+ }
+ }
+
+ for (int j = 0; j < this.columnList.size(); j++) {
+ WColumn column = this.columnList.get(j);
+ Cell firstCell = firstRow.createCell(j + offset);
+ String columnName = column.getName();
+ XSSFRichTextString textString;
+ if (column.isRequired()) {
+ textString = new XSSFRichTextString("*" + columnName);
+ textString.applyFont(0, 1, new RedFont(workbook).getFont());
+ textString.applyFont(1, textString.length(), workbook.createFont());
+ } else {
+ textString = new XSSFRichTextString(columnName);
+ textString.applyFont(workbook.createFont());
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(column.getDescription()).append("\n");
+
+ // 如果填写了注释信息
+ if (sb.length() > 1) {
+ XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);
+ XSSFComment comment = drawing.createCellComment(anchor);
+ comment.setString(sb.toString());
+ firstCell.setCellComment(comment);
+ }
+ firstCell.setCellValue(textString);
+ firstCell.setCellStyle(new HeadCellStyle(workbook).getStyle());
+ sheet.setColumnWidth(j + offset, (4 + column.getCellWidth()) * 256);
+
+ if (column.getCellList() != null){
+ CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 65535, j+offset, j+offset);
+ DataValidationHelper helper = sheet.getDataValidationHelper();
+ DataValidationConstraint constraint = helper.createExplicitListConstraint(column.getCellList());
+ DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
+ //处理Excel兼容性问题
+ if (dataValidation instanceof XSSFDataValidation) {
+ dataValidation.setSuppressDropDownArrow(true);
+ dataValidation.setShowErrorBox(true);
+ } else {
+ dataValidation.setSuppressDropDownArrow(false);
+ }
+
+ dataValidation.setEmptyCellAllowed(true);
+ dataValidation.setShowPromptBox(true);
+ dataValidation.createPromptBox("规则", "请选择下拉框里面的数据");
+ sheet.addValidationData(dataValidation);
+ }
+ }
+
+ // 冻结第一行
+ if (freezeFirst) {
+ sheet.createFreezePane(255, 1);
+ }
+
+ // 填充数据
+ for (int i = 0; i < this.rowList.size(); i++) {
+ WRow wRow = this.rowList.get(i);
+ Row row = sheet.createRow(i + 1);
+
+ if (offset > 0) {
+ if (this.rowList.get(i).hasError()) {
+ // 添加结果
+ List errorList = wRow.getErrorList();
+ Cell resultCell = row.createCell(0);
+ resultCell.setCellStyle(new ErrorCellStyle(workbook).getStyle());
+ resultCell.setCellValue("错误");
+ // 添加错误信息详细说明
+ Cell errsCell = row.createCell(1);
+ errsCell.setCellStyle(new ErrorCellStyle(workbook).getStyle());
+ String join = String.join(";\n", errorList);
+ errsCell.setCellValue(new XSSFRichTextString(join));
+ } else {
+ // 添加结果
+ Cell resultCell = row.createCell(0);
+ resultCell.setCellStyle(new SuccessCellStyle(workbook).getStyle());
+ resultCell.setCellValue("成功");
+ // 添加错误信息详细说明
+ Cell errsCell = row.createCell(1);
+ errsCell.setCellStyle(new SuccessCellStyle(workbook).getStyle());
+ errsCell.setCellValue("");
+ }
+ }
+
+ for (int j = 0; j < this.columnList.size(); j++) {
+ WColumn column = this.columnList.get(j);
+
+ Cell xssfCell = row.createCell(j + offset);
+ WCell WCell = this.rowList.get(i).get(column.getName());
+ if (null == WCell) {
+ continue;
+ }
+ String value = WCell.getValue();
+ xssfCell.setCellType(column.getCellType());
+ if (column.getCellType() == Cell.CELL_TYPE_NUMERIC || column.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
+ xssfCell.setCellStyle(new DataCellStyle(workbook, CellStyle.ALIGN_RIGHT, wRow.hasError()).getStyle());
+ } else {
+ xssfCell.setCellStyle(new DataCellStyle(workbook, CellStyle.ALIGN_LEFT, wRow.hasError()).getStyle());
+ }
+
+ xssfCell.setCellValue(value);
+ }
+ }
+ return workbook;
+ }
+
+ /**
+ * 获取单元格的值
+ *
+ * @param cell 要获取值的单元格
+ * @return 单元格的值
+ */
+ public static String getValue(Cell cell) {
+ if (cell == null) {
+ return "";
+ }
+ switch (cell.getCellType()) {
+ case Cell.CELL_TYPE_STRING:
+ return cell.getStringCellValue();
+ case Cell.CELL_TYPE_BOOLEAN:
+ return String.valueOf(cell.getBooleanCellValue());
+ case Cell.CELL_TYPE_NUMERIC:
+ if (HSSFDateUtil.isCellDateFormatted(cell)) {
+ Date value = cell.getDateCellValue();
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value);
+ } else {
+ return NumberToTextConverter.toText(cell.getNumericCellValue());
+ }
+ default:
+ return cell.getStringCellValue();
+ }
+ }
+
+ public interface Processor {
+ List exec(T t);
+ }
+
+ public void toFile(File file) throws IOException {
+ File parentFile = file.getParentFile();
+ if (!parentFile.exists() && !parentFile.mkdirs()) {
+ throw new RuntimeException("路径创建失败");
+ }
+ if (!file.exists() && !file.createNewFile()) {
+ throw new RuntimeException("文件创建失败");
+ }
+ FileOutputStream fileOutputStream = new FileOutputStream(file);
+ fileOutputStream.write(getBytes());
+ fileOutputStream.close();
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/WRow.java b/src/main/java/xyz/wbsite/frame/excel/WRow.java
new file mode 100644
index 0000000..2e998dd
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/WRow.java
@@ -0,0 +1,34 @@
+package xyz.wbsite.frame.excel;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * WRow - Excel行对象,即数据WCell容器
继承至HashMap,key为列名,value为单元对象
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class WRow extends HashMap implements Serializable {
+
+ private List errorList = new ArrayList<>();
+
+ public final boolean hasError() {
+ return errorList.size() > 0;
+ }
+
+ public final void addError(String errorMsg) {
+ errorList.add(errorMsg);
+ }
+
+ public final void addErrors(List errorMsgs) {
+ errorList.addAll(errorMsgs);
+ }
+
+ public List getErrorList() {
+ return errorList;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnDescription.java b/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnDescription.java
new file mode 100644
index 0000000..ac06c42
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnDescription.java
@@ -0,0 +1,22 @@
+package xyz.wbsite.frame.excel.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * ColumnDescription - Excel列描述注解
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ColumnDescription {
+ String value() default "";
+
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnList.java b/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnList.java
new file mode 100644
index 0000000..c8a9abb
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnList.java
@@ -0,0 +1,25 @@
+package xyz.wbsite.frame.excel.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * ColumnList - 单元格下拉选项
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ColumnList {
+
+ /**
+ * 下拉列表
+ */
+ String[] value();
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnName.java b/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnName.java
new file mode 100644
index 0000000..0df4b63
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/annotation/ColumnName.java
@@ -0,0 +1,40 @@
+package xyz.wbsite.frame.excel.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * ColumnName - Excel列名称注解,当Excel模板没有该注解则使用字段名作为列名称
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ColumnName {
+
+ /**
+ * 列名
+ */
+ String value();
+
+ /**
+ * 默认宽度
+ */
+ int width() default 8;
+
+ /**
+ * *标志
+ */
+ boolean required() default false;
+
+ /**
+ * 日期格式化
+ */
+ String dateFormat() default "yyyy-MM-dd";
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/annotation/Convert.java b/src/main/java/xyz/wbsite/frame/excel/annotation/Convert.java
new file mode 100644
index 0000000..8b332a1
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/annotation/Convert.java
@@ -0,0 +1,21 @@
+package xyz.wbsite.frame.excel.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Converter - Excel列转化器注解
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Convert {
+ Class target();
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/annotation/Ignore.java b/src/main/java/xyz/wbsite/frame/excel/annotation/Ignore.java
new file mode 100644
index 0000000..9540028
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/annotation/Ignore.java
@@ -0,0 +1,21 @@
+package xyz.wbsite.frame.excel.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Ignore - Excel列忽略注解,在导入导出过程中不会对存在该注解的字典进行解析
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Ignore {
+ boolean value() default true;
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/annotation/ParentFirst.java b/src/main/java/xyz/wbsite/frame/excel/annotation/ParentFirst.java
new file mode 100644
index 0000000..c169b8d
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/annotation/ParentFirst.java
@@ -0,0 +1,21 @@
+package xyz.wbsite.frame.excel.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * ParentFirst - 是否读取父类的属性,默认否
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ParentFirst {
+ boolean value() default true;
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/annotation/SheetName.java b/src/main/java/xyz/wbsite/frame/excel/annotation/SheetName.java
new file mode 100644
index 0000000..e1b7f24
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/annotation/SheetName.java
@@ -0,0 +1,23 @@
+package xyz.wbsite.frame.excel.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * SheetName - 工作表名称,当Excel模板没有该注解则使用Class类名作为工作表默认名称
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SheetName {
+ String value();
+
+ boolean freezeFirst() default false;
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/BooleanConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/BooleanConverter.java
new file mode 100644
index 0000000..a233558
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/BooleanConverter.java
@@ -0,0 +1,46 @@
+package xyz.wbsite.frame.excel.converter;
+
+import xyz.wbsite.frame.excel.exception.ValueConverterException;
+
+/**
+ * BooleanConverter - Boolean转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class BooleanConverter implements Converter {
+
+ @Override
+ public Boolean convert(String var) throws ValueConverterException {
+ if (null == var || "".equals(var)) {
+ return false;
+ }
+
+ String lowerCase = var.toLowerCase();
+
+ if (lowerCase.matches("y|n")) {
+ return "y".equals(lowerCase);
+ } else if (lowerCase.matches("yes|no")) {
+ return "yes".equals(lowerCase);
+ } else if (lowerCase.matches("true|false")) {
+ return "true".equals(lowerCase);
+ } else if (lowerCase.matches("是|否")) {
+ return "是".equals(lowerCase);
+ } else if (lowerCase.matches("有|无")) {
+ return "有".equals(lowerCase);
+ } else if (lowerCase.matches("是|不是")) {
+ return "是".equals(lowerCase);
+ } else {
+ throw new ValueConverterException("[" + var + "] can not convert to Boolean");
+ }
+ }
+
+ @Override
+ public String string(Boolean var) {
+ if (var == null) {
+ return "";
+ }
+ return var ? "是" : "否";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/ByteConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/ByteConverter.java
new file mode 100644
index 0000000..b05ecef
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/ByteConverter.java
@@ -0,0 +1,28 @@
+package xyz.wbsite.frame.excel.converter;
+
+/**
+ * ByteConverter - Byte转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class ByteConverter implements Converter {
+
+ @Override
+ public Byte convert(String var) {
+ try {
+ return Byte.parseByte(var);
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ @Override
+ public String string(Byte var) {
+ if (var == null) {
+ return "";
+ }
+ return String.valueOf(var);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/CharacterConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/CharacterConverter.java
new file mode 100644
index 0000000..795dacb
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/CharacterConverter.java
@@ -0,0 +1,28 @@
+package xyz.wbsite.frame.excel.converter;
+
+/**
+ * CharacterConverter - Character转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class CharacterConverter implements Converter {
+
+ @Override
+ public Character convert(String var) {
+ if (var == null || var.equals("")) {
+ return '0';
+ } else {
+ return var.charAt(0);
+ }
+ }
+
+ @Override
+ public String string(Character var) {
+ if (var == null) {
+ return "";
+ }
+ return String.valueOf(var).trim();
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/Converter.java b/src/main/java/xyz/wbsite/frame/excel/converter/Converter.java
new file mode 100644
index 0000000..13243cb
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/Converter.java
@@ -0,0 +1,17 @@
+package xyz.wbsite.frame.excel.converter;
+
+import xyz.wbsite.frame.excel.exception.ValueConverterException;
+
+/**
+ * Converter - 转化器接口,所有转化器必须实现该接口
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public interface Converter {
+
+ T convert(String var) throws ValueConverterException;
+
+ String string(T var);
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/DateConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/DateConverter.java
new file mode 100644
index 0000000..ab3e13f
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/DateConverter.java
@@ -0,0 +1,51 @@
+package xyz.wbsite.frame.excel.converter;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * DateConverter - Date转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class DateConverter implements Converter {
+
+ @Override
+ public Date convert(String var) {
+ if (var == null) {
+ return null;
+ }
+ Date date = null;
+ try {
+ var = var.trim();
+ if (var.matches("[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}")) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ return sdf.parse(var);
+ } else if (var.matches("[0-9]{4}/[0-9]{1,2}/[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}")) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ return sdf.parse(var);
+ } else if (var.matches("[0-9]{4}-[0-9]{1,2}-[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}")) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ date = sdf.parse(var);
+ } else if (var.matches("[0-9]{4}年[0-9]{1,2}月[0-9]{1,2}日 [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}")) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
+ date = sdf.parse(var);
+ }
+
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return date;
+ }
+
+ @Override
+ public String string(Date var) {
+ if (var == null) {
+ return "";
+ }
+ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(var);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/DoubleConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/DoubleConverter.java
new file mode 100644
index 0000000..06f55ea
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/DoubleConverter.java
@@ -0,0 +1,28 @@
+package xyz.wbsite.frame.excel.converter;
+
+/**
+ * DoubleConverter - Double转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class DoubleConverter implements Converter {
+
+ @Override
+ public Double convert(String var) {
+ try {
+ return Double.parseDouble(var);
+ } catch (Exception e) {
+ return 0d;
+ }
+ }
+
+ @Override
+ public String string(Double var) {
+ if (var == null) {
+ return "";
+ }
+ return String.valueOf(var);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/FloatConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/FloatConverter.java
new file mode 100644
index 0000000..647a289
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/FloatConverter.java
@@ -0,0 +1,33 @@
+package xyz.wbsite.frame.excel.converter;
+
+/**
+ * FloatConverter - Float转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class FloatConverter implements Converter {
+
+ @Override
+ public Float convert(String var) {
+ try {
+ //增加对1.0一类的的优化显示
+ if (var.matches("(\\d+)\\.0")) {
+ var = var.replaceAll("\\.0$", "");
+ }
+
+ return Float.parseFloat(var);
+ } catch (Exception e) {
+ return 0f;
+ }
+ }
+
+ @Override
+ public String string(Float var) {
+ if (var == null) {
+ return "";
+ }
+ return String.valueOf(var);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/IntegerConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/IntegerConverter.java
new file mode 100644
index 0000000..264228a
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/IntegerConverter.java
@@ -0,0 +1,28 @@
+package xyz.wbsite.frame.excel.converter;
+
+/**
+ * IntegerConverter - Integer转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class IntegerConverter implements Converter {
+
+ @Override
+ public Integer convert(String var) {
+ try {
+ return Integer.parseInt(var);
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ @Override
+ public String string(Integer var) {
+ if (var == null) {
+ return "";
+ }
+ return String.valueOf(var);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/LongConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/LongConverter.java
new file mode 100644
index 0000000..526de2f
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/LongConverter.java
@@ -0,0 +1,40 @@
+package xyz.wbsite.frame.excel.converter;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * LongConverter - Long转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class LongConverter implements Converter {
+
+ @Override
+ public Long convert(String var) {
+ try {
+ //增加对1.0一类的的兼容性
+ if (var.matches("(\\d+)\\.(\\d*)")) {
+ Pattern compile = Pattern.compile("(\\d+)\\.(\\d*)");
+ Matcher matcher = compile.matcher(var);
+ if (matcher.find()) {
+ var = matcher.group(1);
+ }
+ }
+
+ return Long.parseLong(var);
+ } catch (Exception e) {
+ return 0L;
+ }
+ }
+
+ @Override
+ public String string(Long var) {
+ if (var == null) {
+ return "";
+ }
+ return String.valueOf(var);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/ShortConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/ShortConverter.java
new file mode 100644
index 0000000..5ddebb1
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/ShortConverter.java
@@ -0,0 +1,28 @@
+package xyz.wbsite.frame.excel.converter;
+
+/**
+ * ShortConverter - Short转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class ShortConverter implements Converter {
+
+ @Override
+ public Short convert(String var) {
+ try {
+ return Short.parseShort(var);
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ @Override
+ public String string(Short var) {
+ if (var == null) {
+ return "";
+ }
+ return String.valueOf(var);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/converter/StringConverter.java b/src/main/java/xyz/wbsite/frame/excel/converter/StringConverter.java
new file mode 100644
index 0000000..db00521
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/converter/StringConverter.java
@@ -0,0 +1,24 @@
+package xyz.wbsite.frame.excel.converter;
+
+/**
+ * StringConverter - String转化器,重写了对象到String,String到对象的转化方式
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class StringConverter implements Converter {
+
+ @Override
+ public String convert(String var) {
+ return var != null ? var.trim() : null;
+ }
+
+ @Override
+ public String string(String var) {
+ if (var == null) {
+ return "";
+ }
+ return String.valueOf(var);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/exception/ReadErrorException.java b/src/main/java/xyz/wbsite/frame/excel/exception/ReadErrorException.java
new file mode 100644
index 0000000..9dac0cf
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/exception/ReadErrorException.java
@@ -0,0 +1,17 @@
+package xyz.wbsite.frame.excel.exception;
+
+/**
+ * Excel文件读取失败异常
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class ReadErrorException extends Exception {
+ public ReadErrorException() {
+ }
+
+ public ReadErrorException(String s) {
+ super(s);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/exception/TemplateNotMatchException.java b/src/main/java/xyz/wbsite/frame/excel/exception/TemplateNotMatchException.java
new file mode 100644
index 0000000..37887cf
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/exception/TemplateNotMatchException.java
@@ -0,0 +1,17 @@
+package xyz.wbsite.frame.excel.exception;
+
+/**
+ * Excel文件与模板不匹配时异常
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class TemplateNotMatchException extends Exception {
+ public TemplateNotMatchException() {
+ }
+
+ public TemplateNotMatchException(String s) {
+ super(s);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/exception/ValueConverterException.java b/src/main/java/xyz/wbsite/frame/excel/exception/ValueConverterException.java
new file mode 100644
index 0000000..b848c46
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/exception/ValueConverterException.java
@@ -0,0 +1,15 @@
+package xyz.wbsite.frame.excel.exception;
+
+/**
+ * 值转换异常
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class ValueConverterException extends Exception {
+
+ public ValueConverterException(String s) {
+ super(s);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/style/BaseCellStyle.java b/src/main/java/xyz/wbsite/frame/excel/style/BaseCellStyle.java
new file mode 100644
index 0000000..d336a29
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/style/BaseCellStyle.java
@@ -0,0 +1,57 @@
+package xyz.wbsite.frame.excel.style;
+
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * Created on 2015/1/29.
+ *
+ * @author
+ * @since 2.0.0
+ */
+public class BaseCellStyle {
+ /**
+ * 样式
+ */
+ protected CellStyle style;
+
+ public BaseCellStyle(Workbook workbook) {
+ style = workbook.createCellStyle();
+ style.setFillPattern(CellStyle.NO_FILL);
+ //下边框
+ style.setBorderBottom(CellStyle.SOLID_FOREGROUND);
+ //下边框颜色
+ style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+ //左边框
+ style.setBorderLeft(CellStyle.SOLID_FOREGROUND);
+ //左边框颜色
+ style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+ //右边框
+ style.setBorderRight(CellStyle.SOLID_FOREGROUND);
+ //右边框颜色
+ style.setRightBorderColor(IndexedColors.BLACK.getIndex());
+ //上边框
+ style.setBorderTop(CellStyle.SOLID_FOREGROUND);
+ //上边框颜色
+ style.setTopBorderColor(IndexedColors.BLACK.getIndex());
+
+ style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //上下居中
+ style.setBorderBottom(CellStyle.SOLID_FOREGROUND); //下边框
+ style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); //下边框颜色
+ style.setBorderLeft(CellStyle.SOLID_FOREGROUND); //左边框
+ style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); //左边框颜色
+ style.setBorderRight(CellStyle.SOLID_FOREGROUND); //右边框
+ style.setRightBorderColor(IndexedColors.BLACK.getIndex()); //右边框颜色
+ style.setBorderTop(CellStyle.SOLID_FOREGROUND); //上边框
+ style.setTopBorderColor(IndexedColors.BLACK.getIndex()); //上边框颜色
+ }
+
+ public CellStyle getStyle() {
+ return style;
+ }
+
+ public void setStyle(CellStyle style) {
+ this.style = style;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/style/BaseFont.java b/src/main/java/xyz/wbsite/frame/excel/style/BaseFont.java
new file mode 100644
index 0000000..e03c689
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/style/BaseFont.java
@@ -0,0 +1,29 @@
+package xyz.wbsite.frame.excel.style;
+
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * Created on 2015/1/29.
+ *
+ * @author
+ * @since 2.0.0
+ */
+public class BaseFont {
+ /**
+ * 字体
+ */
+ protected Font font;
+
+ public BaseFont(Workbook workbook) {
+ font = workbook.createFont();
+ }
+
+ public Font getFont() {
+ return font;
+ }
+
+ public void setFont(Font font) {
+ this.font = font;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/style/DataCellStyle.java b/src/main/java/xyz/wbsite/frame/excel/style/DataCellStyle.java
new file mode 100644
index 0000000..583921c
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/style/DataCellStyle.java
@@ -0,0 +1,29 @@
+package xyz.wbsite.frame.excel.style;
+
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Workbook;
+
+public class DataCellStyle extends BaseCellStyle {
+
+ public DataCellStyle(Workbook workbook, short align, boolean error) {
+ super(workbook);
+ style.setAlignment(align);
+ if (error) {
+ style.setFillForegroundColor(HSSFColor.RED.index); //背景颜色红色
+ style.setFillPattern(CellStyle.SOLID_FOREGROUND); //设置单元格填充样式
+ }
+ }
+
+ public DataCellStyle(Workbook workbook, short align) {
+ this(workbook, align, false);
+ }
+
+ public DataCellStyle(Workbook workbook, boolean error) {
+ this(workbook, CellStyle.ALIGN_LEFT, error);
+ }
+
+ public DataCellStyle(Workbook workbook) {
+ this(workbook, CellStyle.ALIGN_LEFT, false);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/style/ErrorCellStyle.java b/src/main/java/xyz/wbsite/frame/excel/style/ErrorCellStyle.java
new file mode 100644
index 0000000..b8afb2b
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/style/ErrorCellStyle.java
@@ -0,0 +1,22 @@
+package xyz.wbsite.frame.excel.style;
+
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Workbook;
+
+public class ErrorCellStyle extends BaseCellStyle {
+
+ public ErrorCellStyle(Workbook workbook) {
+ super(workbook);
+ style.setFillForegroundColor(HSSFColor.RED.index); //背景颜色红色
+ style.setFillPattern(CellStyle.SOLID_FOREGROUND); //设置单元格填充样式
+ }
+
+ public CellStyle getStyle() {
+ return style;
+ }
+
+ public void setStyle(CellStyle style) {
+ this.style = style;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/style/HeadCellStyle.java b/src/main/java/xyz/wbsite/frame/excel/style/HeadCellStyle.java
new file mode 100644
index 0000000..10eb9ab
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/style/HeadCellStyle.java
@@ -0,0 +1,15 @@
+package xyz.wbsite.frame.excel.style;
+
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Workbook;
+
+public class HeadCellStyle extends BaseCellStyle {
+ public HeadCellStyle(Workbook workbook) {
+ super(workbook);
+ style.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index); //背景颜色-灰色
+ style.setFillPattern(CellStyle.SOLID_FOREGROUND); // 设置单元格填充样式
+ style.setAlignment(CellStyle.ALIGN_CENTER); // 居中
+ style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);//上下居中
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/style/NormalFont.java b/src/main/java/xyz/wbsite/frame/excel/style/NormalFont.java
new file mode 100644
index 0000000..f4cf5bb
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/style/NormalFont.java
@@ -0,0 +1,18 @@
+package xyz.wbsite.frame.excel.style;
+
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * 普通字体.颜色黑
+ * Created on 2015/1/29.
+ *
+ * @author
+ * @since 2.0.0
+ */
+public class NormalFont extends BaseFont {
+ public NormalFont(Workbook workbook) {
+ super(workbook);
+ font.setColor(HSSFColor.BLACK.index); //字体颜色-黑色
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/style/RedFont.java b/src/main/java/xyz/wbsite/frame/excel/style/RedFont.java
new file mode 100644
index 0000000..9d93a92
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/style/RedFont.java
@@ -0,0 +1,18 @@
+package xyz.wbsite.frame.excel.style;
+
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * 普通字体.颜色黑
+ * Created on 2015/1/29.
+ *
+ * @author
+ * @since 2.0.0
+ */
+public class RedFont extends BaseFont {
+ public RedFont(Workbook workbook) {
+ super(workbook);
+ font.setColor(HSSFColor.RED.index); //字体颜色-黑色
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/excel/style/SuccessCellStyle.java b/src/main/java/xyz/wbsite/frame/excel/style/SuccessCellStyle.java
new file mode 100644
index 0000000..136c474
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/excel/style/SuccessCellStyle.java
@@ -0,0 +1,22 @@
+package xyz.wbsite.frame.excel.style;
+
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Workbook;
+
+public class SuccessCellStyle extends BaseCellStyle {
+
+ public SuccessCellStyle(Workbook workbook) {
+ super(workbook);
+ style.setFillForegroundColor(HSSFColor.GREEN.index); //背景颜色红色
+ style.setFillPattern(CellStyle.SOLID_FOREGROUND); //设置单元格填充样式
+ }
+
+ public CellStyle getStyle() {
+ return style;
+ }
+
+ public void setStyle(CellStyle style) {
+ this.style = style;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/schedule/RunCronTask.java b/src/main/java/xyz/wbsite/frame/schedule/RunCronTask.java
new file mode 100644
index 0000000..edbb08f
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/schedule/RunCronTask.java
@@ -0,0 +1,18 @@
+package xyz.wbsite.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 {
+
+ abstract String cron();
+
+ @Override
+ public ScheduledFuture> schedule(ThreadPoolTaskScheduler poolTaskScheduler) {
+ Assert.notNull(poolTaskScheduler, "ThreadPoolTaskScheduler must not be null");
+ return poolTaskScheduler.schedule(this, new CronTrigger(cron()));
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/schedule/RunDelayRepeatTask.java b/src/main/java/xyz/wbsite/frame/schedule/RunDelayRepeatTask.java
new file mode 100644
index 0000000..f52c639
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/schedule/RunDelayRepeatTask.java
@@ -0,0 +1,18 @@
+package xyz.wbsite.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());
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/schedule/RunFixRepeatTask.java b/src/main/java/xyz/wbsite/frame/schedule/RunFixRepeatTask.java
new file mode 100644
index 0000000..1abf7e6
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/schedule/RunFixRepeatTask.java
@@ -0,0 +1,18 @@
+package xyz.wbsite.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());
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/schedule/RunSqlTask.java b/src/main/java/xyz/wbsite/frame/schedule/RunSqlTask.java
new file mode 100644
index 0000000..5858ed7
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/schedule/RunSqlTask.java
@@ -0,0 +1,40 @@
+package xyz.wbsite.frame.schedule;
+
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import xyz.wbsite.frame.auth.LocalData;
+import xyz.wbsite.frame.utils.LogUtil;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+public abstract class RunSqlTask extends RunFixRepeatTask {
+
+ private Connection connection;
+
+ @Override
+ public void run() {
+ try {
+ if (connection == null || connection.isClosed()) {
+ SqlSessionFactory factory = LocalData.getBean(SqlSessionFactory.class);
+ SqlSession sqlSession = factory.openSession(true);
+ connection = sqlSession.getConnection();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ LogUtil.e("schedule: get connection failed!");
+ return;
+ }
+ try {
+ PreparedStatement preparedStatement = connection.prepareStatement(getSql());
+ preparedStatement.execute();
+ preparedStatement.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ LogUtil.e("RunSqlTask exec failed! SQL:[" + getSql() + "]");
+ }
+ }
+
+ public abstract String getSql();
+}
diff --git a/src/main/java/xyz/wbsite/frame/schedule/RunTask.java b/src/main/java/xyz/wbsite/frame/schedule/RunTask.java
new file mode 100644
index 0000000..897dea6
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/schedule/RunTask.java
@@ -0,0 +1,21 @@
+package xyz.wbsite.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 abstract ScheduledFuture> schedule(ThreadPoolTaskScheduler poolTaskScheduler);
+
+ public void configChange(ThreadPoolTaskScheduler scheduler) {
+ ScheduledFuture> schedule = scheduler.schedule(this, new Date());
+ if (!schedule.cancel(true)) {
+
+ }
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/AESUtil.java b/src/main/java/xyz/wbsite/frame/utils/AESUtil.java
new file mode 100644
index 0000000..7f42706
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/AESUtil.java
@@ -0,0 +1,110 @@
+package xyz.wbsite.frame.utils;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * AESUtil 对称加密和解密工具类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class AESUtil {
+
+ private static final String ALGORITHM = "AES";
+ private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";
+
+ /**
+ * 加密
+ *
+ * @param data 待加密字节数组
+ * @param secret 密钥
+ * @return base64字符串
+ */
+ public static byte[] encrypt(byte[] data, String secret) {
+ try {
+ if (secret.length() != 16) {
+ throw new IllegalArgumentException("secret's length is not 16");
+ }
+ SecretKeySpec key = new SecretKeySpec(secret.getBytes(), ALGORITHM);
+ Cipher cipher = Cipher.getInstance(ALGORITHM_STR); // 创建密码器
+ cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
+ return cipher.doFinal(data);// 加密
+ } catch (NoSuchPaddingException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 加密
+ *
+ * @param data 待加密字节数组
+ * @param secret 密钥
+ * @return base64字符串
+ */
+ public static String encrypt2Base64(byte[] data, String secret) {
+ byte[] encrypt = encrypt(data, secret);
+ return Base64Util.encodeToString(encrypt, false);
+ }
+
+ /**
+ * 解密
+ *
+ * @param data 待解密字节数组
+ * @param secret 密钥
+ * @return
+ */
+ public static byte[] decrypt(byte[] data, String secret) {
+ try {
+ if (secret.length() != 16) {
+ throw new IllegalArgumentException("secret's length is not 16");
+ }
+ SecretKeySpec key = new SecretKeySpec(secret.getBytes(), ALGORITHM);
+ Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
+ cipher.init(Cipher.DECRYPT_MODE, key);
+ return cipher.doFinal(data);
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static byte[] decryptBase64(String base64Data, String secret) {
+ byte[] decode = Base64Util.decode(base64Data);
+ return decrypt(decode, secret);
+ }
+
+ public static String decrypt2String(String base64Data, String secret) {
+ byte[] bytes = decryptBase64(base64Data, secret);
+ try {
+ return new String(bytes, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/frame/utils/Base64Util.java b/src/main/java/xyz/wbsite/frame/utils/Base64Util.java
new file mode 100644
index 0000000..614c782
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/Base64Util.java
@@ -0,0 +1,497 @@
+package xyz.wbsite.frame.utils;
+
+import java.util.Arrays;
+
+/**
+ * Base64Util
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class Base64Util {
+ private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
+ private static final int[] IA = new int[256];
+
+ static {
+ Arrays.fill(IA, -1);
+ for (int i = 0, iS = CA.length; i < iS; i++)
+ IA[CA[i]] = i;
+ IA['='] = 0;
+ }
+
+ public final static String encodeToString(byte[] sArr) {
+ return new String(encodeToChar(sArr, false));
+ }
+
+ public final static char[] encodeToChar(byte[] sArr, boolean lineSep) {
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0)
+ return new char[0];
+
+ int eLen = (sLen / 3) * 3; // Length of even 24-bits.
+ int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
+ int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
+ char[] dArr = new char[dLen];
+
+ // Encode even 24-bits
+ for (int s = 0, d = 0, cc = 0; s < eLen; ) {
+ // Copy next three bytes into lower 24 bits of int, paying attension to sign.
+ int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
+
+ // Encode the int into four chars
+ dArr[d++] = CA[(i >>> 18) & 0x3f];
+ dArr[d++] = CA[(i >>> 12) & 0x3f];
+ dArr[d++] = CA[(i >>> 6) & 0x3f];
+ dArr[d++] = CA[i & 0x3f];
+
+ // Add optional line separator
+ if (lineSep && ++cc == 19 && d < dLen - 2) {
+ dArr[d++] = '\r';
+ dArr[d++] = '\n';
+ cc = 0;
+ }
+ }
+
+ // Pad and encode last bits if source isn't even 24 bits.
+ int left = sLen - eLen; // 0 - 2.
+ if (left > 0) {
+ // Prepare the int
+ int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
+
+ // Set last four chars
+ dArr[dLen - 4] = CA[i >> 12];
+ dArr[dLen - 3] = CA[(i >>> 6) & 0x3f];
+ dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
+ dArr[dLen - 1] = '=';
+ }
+ return dArr;
+ }
+
+ /**
+ * Encodes a raw byte array into a BASE64 String
representation i accordance with RFC 2045.
+ *
+ * @param sArr The bytes to convert. If null
or length 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null
.
+ */
+ public final static String encodeToString(byte[] sArr, boolean lineSep) {
+ // Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
+ return new String(encodeToChar(sArr, lineSep));
+ }
+
+ /**
+ * Encodes a raw byte array into a BASE64 byte[]
representation i accordance with RFC 2045.
+ *
+ * @param sArr The bytes to convert. If null
or length 0 an empty array will be returned.
+ * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
+ * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
+ * little faster.
+ * @return A BASE64 encoded array. Never null
.
+ */
+ public final static byte[] encodeToByte(byte[] sArr, boolean lineSep) {
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0)
+ return new byte[0];
+
+ int eLen = (sLen / 3) * 3; // Length of even 24-bits.
+ int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
+ int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
+ byte[] dArr = new byte[dLen];
+
+ // Encode even 24-bits
+ for (int s = 0, d = 0, cc = 0; s < eLen; ) {
+ // Copy next three bytes into lower 24 bits of int, paying attension to sign.
+ int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
+
+ // Encode the int into four chars
+ dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
+ dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
+ dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
+ dArr[d++] = (byte) CA[i & 0x3f];
+
+ // Add optional line separator
+ if (lineSep && ++cc == 19 && d < dLen - 2) {
+ dArr[d++] = '\r';
+ dArr[d++] = '\n';
+ cc = 0;
+ }
+ }
+
+ // Pad and encode last bits if source isn't an even 24 bits.
+ int left = sLen - eLen; // 0 - 2.
+ if (left > 0) {
+ // Prepare the int
+ int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
+
+ // Set last four chars
+ dArr[dLen - 4] = (byte) CA[i >> 12];
+ dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
+ dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
+ dArr[dLen - 1] = '=';
+ }
+ return dArr;
+ }
+
+ public final static byte[] decode(char[] sArr) {
+ // Check special case
+ int sLen = sArr != null ? sArr.length : 0;
+ if (sLen == 0)
+ return new byte[0];
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IA[sArr[i]] < 0)
+ sepCnt++;
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0)
+ return null;
+
+ int pad = 0;
+ for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0; )
+ if (sArr[i] == '=')
+ pad++;
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IA[sArr[s++]];
+ if (c >= 0)
+ i |= c << (18 - j * 6);
+ else
+ j--;
+ }
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++] = (byte) (i >> 8);
+ if (d < len)
+ dArr[d++] = (byte) i;
+ }
+ }
+ return dArr;
+ }
+
+ /**
+ * Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
+ * and without line separators.
+ *
+ * @param sArr The source array. Length 0 will return an empty array. null
will throw an exception.
+ * @return The decoded array of bytes. May be of length 0. Will be null
if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ */
+ public final static byte[] decode(byte[] sArr) {
+ // Check special case
+ int sLen = sArr.length;
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IA[sArr[i] & 0xff] < 0)
+ sepCnt++;
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0)
+ return null;
+
+ int pad = 0;
+ for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0; )
+ if (sArr[i] == '=')
+ pad++;
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IA[sArr[s++] & 0xff];
+ if (c >= 0)
+ i |= c << (18 - j * 6);
+ else
+ j--;
+ }
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++] = (byte) (i >> 8);
+ if (d < len)
+ dArr[d++] = (byte) i;
+ }
+ }
+
+ return dArr;
+ }
+
+ /**
+ * Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
+ * fast as {@link =#=decode(byte[])}. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ *
+ * @param sArr The source array. Length 0 will return an empty array. null
will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ */
+ public final static byte[] decodeFast(byte[] sArr) {
+ // Check special case
+ int sLen = sArr.length;
+ if (sLen == 0)
+ return new byte[0];
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0)
+ sIx++;
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0)
+ eIx--;
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++)
+ i |= IA[sArr[sIx++]] << (18 - j * 6);
+
+ for (int r = 16; d < len; r -= 8)
+ dArr[d++] = (byte) (i >> r);
+ }
+
+ return dArr;
+ }
+
+ /**
+ * Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
+ * fast as {@link =#=decode(char[])}. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ *
+ * @param sArr The source array. Length 0 will return an empty array. null
will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ */
+ public final static byte[] decodeFast(char[] sArr) {
+ // Check special case
+ int sLen = sArr.length;
+ if (sLen == 0)
+ return new byte[0];
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IA[sArr[sIx]] < 0)
+ sIx++;
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IA[sArr[eIx]] < 0)
+ eIx--;
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++)
+ i |= IA[sArr[sIx++]] << (18 - j * 6);
+
+ for (int r = 16; d < len; r -= 8)
+ dArr[d++] = (byte) (i >> r);
+ }
+
+ return dArr;
+ }
+
+ /**
+ * Decodes a BASE64 encoded String
. All illegal characters will be ignored and can handle both strings with
+ * and without line separators.
+ * Note! It can be up to about 2x the speed to call decode(str.toCharArray())
instead. That
+ * will create a temporary array though. This version will use str.charAt(i)
to iterate the string.
+ *
+ * @param str The source string. null
or length 0 will return an empty array.
+ * @return The decoded array of bytes. May be of length 0. Will be null
if the legal characters
+ * (including '=') isn't divideable by 4. (I.e. definitely corrupted).
+ */
+ public final static byte[] decode(String str) {
+ // Check special case
+ int sLen = str != null ? str.length() : 0;
+ if (sLen == 0)
+ return new byte[0];
+
+ // Count illegal characters (including '\r', '\n') to know what size the returned array will be,
+ // so we don't have to reallocate & copy it later.
+ int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
+ for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
+ if (IA[str.charAt(i)] < 0)
+ sepCnt++;
+
+ // Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
+ if ((sLen - sepCnt) % 4 != 0)
+ return null;
+
+ // Count '=' at end
+ int pad = 0;
+ for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0; )
+ if (str.charAt(i) == '=')
+ pad++;
+
+ int len = ((sLen - sepCnt) * 6 >> 3) - pad;
+
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ for (int s = 0, d = 0; d < len; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = 0;
+ for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
+ int c = IA[str.charAt(s++)];
+ if (c >= 0)
+ i |= c << (18 - j * 6);
+ else
+ j--;
+ }
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ if (d < len) {
+ dArr[d++] = (byte) (i >> 8);
+ if (d < len)
+ dArr[d++] = (byte) i;
+ }
+ }
+ return dArr;
+ }
+
+ /**
+ * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
+ * fast as {@link =#=decode(String)}. The preconditions are:
+ * + The array must have a line length of 76 chars OR no line separators at all (one line).
+ * + Line separator must be "\r\n", as specified in RFC 2045
+ * + The array must not contain illegal characters within the encoded string
+ * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.
+ *
+ * @param str The source string. Length 0 will return an empty array. null
will throw an exception.
+ * @return The decoded array of bytes. May be of length 0.
+ */
+ public final static byte[] decodeFast(String str) {
+ // Check special case
+ int sLen = str.length();
+ if (sLen == 0)
+ return new byte[0];
+
+ int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
+
+ // Trim illegal chars from start
+ while (sIx < eIx && IA[str.charAt(sIx) & 0xff] < 0)
+ sIx++;
+
+ // Trim illegal chars from end
+ while (eIx > 0 && IA[str.charAt(eIx) & 0xff] < 0)
+ eIx--;
+
+ // get the padding count (=) (0, 1 or 2)
+ int pad = str.charAt(eIx) == '=' ? (str.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end.
+ int cCnt = eIx - sIx + 1; // Content count including possible separators
+ int sepCnt = sLen > 76 ? (str.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
+
+ int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
+ byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
+
+ // Decode all but the last 0 - 2 bytes.
+ int d = 0;
+ for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
+ // Assemble three bytes into an int from four "valid" characters.
+ int i = IA[str.charAt(sIx++)] << 18 | IA[str.charAt(sIx++)] << 12 | IA[str.charAt(sIx++)] << 6 | IA[str.charAt(sIx++)];
+
+ // Add the bytes
+ dArr[d++] = (byte) (i >> 16);
+ dArr[d++] = (byte) (i >> 8);
+ dArr[d++] = (byte) i;
+
+ // If line separator, jump over it.
+ if (sepCnt > 0 && ++cc == 19) {
+ sIx += 2;
+ cc = 0;
+ }
+ }
+
+ if (d < len) {
+ // Decode last 1-3 bytes (incl '=') into 1-3 bytes
+ int i = 0;
+ for (int j = 0; sIx <= eIx - pad; j++)
+ i |= IA[str.charAt(sIx++)] << (18 - j * 6);
+
+ for (int r = 16; d < len; r -= 8)
+ dArr[d++] = (byte) (i >> r);
+ }
+
+ return dArr;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/ClassUtil.java b/src/main/java/xyz/wbsite/frame/utils/ClassUtil.java
new file mode 100644
index 0000000..30c915a
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/ClassUtil.java
@@ -0,0 +1,114 @@
+package xyz.wbsite.frame.utils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * ClassUtil
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class ClassUtil {
+
+ /**
+ * 获取模板类所有字段
+ *
+ * @param clazz 模板对象
+ * @param parentFirst 是否关注父类的字段
+ * @return
+ */
+ public static Field[] getFields(Class clazz, boolean parentFirst) {
+ Field[] fields = clazz.getDeclaredFields();
+
+ if (parentFirst) {
+ Field[] parentFields = getParentFields(clazz.getSuperclass());
+ return concat(fields, parentFields);
+ }
+ return fields;
+ }
+
+ /**
+ * 判断是不是集合的实现类
+ *
+ * @param clazz
+ * @return
+ */
+ public static boolean isCollection(Class> clazz) {
+ return Collection.class.isAssignableFrom(clazz);
+ }
+
+ /**
+ * 获取GET方法
+ *
+ * @param name 成员变量名
+ * @param pojoClass POJO对象
+ * @return 方法
+ */
+ public static Method getMethod(String name, Class> pojoClass) throws RuntimeException {
+ String getMethodName = "get" + StringUtil.upperFirstWord(name);
+ try {
+ return pojoClass.getMethod(getMethodName);
+ } catch (Exception e) {
+ getMethodName = "is" + StringUtil.upperFirstWord(name);
+ try {
+ return pojoClass.getMethod(getMethodName);
+ } catch (NoSuchMethodException e1) {
+ throw new RuntimeException("can not find[" + name + "]method");
+ }
+ }
+ }
+
+ /**
+ * 获取SET方法
+ *
+ * @param name 成员变量名
+ * @param pojoClass POJO对象
+ * @return 方法
+ */
+ public static Method setMethod(String name, Class> pojoClass, Class> type) {
+ String setMethodName = "set" + StringUtil.upperFirstWord(name);
+ try {
+ return pojoClass.getMethod(setMethodName, type);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static boolean isJavaClass(Field field) {
+ Class> fieldType = field.getType();
+ boolean isBaseClass = false;
+ if (fieldType.isArray()) {
+ isBaseClass = false;
+ } else if (fieldType.isPrimitive() || fieldType.getPackage() == null
+ || fieldType.getPackage().getName().equals("java.lang")
+ || fieldType.getPackage().getName().equals("java.math")
+ || fieldType.getPackage().getName().equals("java.sql")
+ || fieldType.getPackage().getName().equals("java.util")) {
+ isBaseClass = true;
+ }
+ return isBaseClass;
+ }
+
+ public static Field[] getFields(Class clazz) {
+ return getFields(clazz, false);
+ }
+
+ private static Field[] getParentFields(Class parentClazz) {
+ if (parentClazz != null) {
+ Field[] fields = parentClazz.getDeclaredFields();
+ Field[] parentFields = getParentFields(parentClazz.getSuperclass());
+ return concat(fields, parentFields);
+ }
+ return new Field[0];
+ }
+
+ private static Field[] concat(Field[] f1, Field[] f2) {
+ Field[] fields = new Field[f1.length + f2.length];
+ System.arraycopy(f1, 0, fields, 0, f1.length);
+ System.arraycopy(f2, 0, fields, f1.length, f2.length);
+ return fields;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/CookieUtil.java b/src/main/java/xyz/wbsite/frame/utils/CookieUtil.java
new file mode 100644
index 0000000..c407f25
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/CookieUtil.java
@@ -0,0 +1,67 @@
+package xyz.wbsite.frame.utils;
+
+import xyz.wbsite.frame.auth.LocalData;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * CookieUtil
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class CookieUtil {
+
+ /**
+ * 通过Cookies获取内容
+ *
+ * @param cookies Cookies
+ * @return passportID
+ */
+ public static String getCookieValue(Cookie[] cookies, String key) {
+ if (cookies != null) {
+ for (Cookie cookie : cookies) {
+ // Cookie中存放的为passport的id ,Cookie名称通过ConfigToolObject获取
+ if (cookie != null && cookie.getName().equals(key)) {
+ try {
+ return cookie.getValue();
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 生成一个默认的Cookie
+ *
+ * @param name 键
+ * @param value 值
+ */
+ public static Cookie newCookie(String name, String value) {
+ HttpServletRequest request = LocalData.getRequest();
+ Cookie cookie = new Cookie(name, value);
+ cookie.setDomain(request.getServerName());
+ 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);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/frame/utils/FileUtil.java b/src/main/java/xyz/wbsite/frame/utils/FileUtil.java
new file mode 100644
index 0000000..e2b015b
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/FileUtil.java
@@ -0,0 +1,137 @@
+package xyz.wbsite.frame.utils;
+
+import java.io.*;
+
+public class FileUtil {
+
+ public static String readFileToString(File file) throws IOException {
+ byte[] bytes = readFileToByteArray(file);
+ return new String(bytes, "UTF-8");
+ }
+
+ public static byte[] readFileToByteArray(File file) throws IOException {
+ InputStream in = openInputStream(file);
+ Throwable var2 = null;
+
+ byte[] var5;
+ try {
+ long fileLength = file.length();
+ var5 = fileLength > 0L ? toByteArray(in, fileLength) : toByteArray(in);
+ } catch (Throwable var14) {
+ var2 = var14;
+ throw var14;
+ } finally {
+ if (in != null) {
+ if (var2 != null) {
+ try {
+ in.close();
+ } catch (Throwable var13) {
+ var2.addSuppressed(var13);
+ }
+ } else {
+ in.close();
+ }
+ }
+
+ }
+
+ return var5;
+ }
+
+ public static FileInputStream openInputStream(File file) throws IOException {
+ if (file.exists()) {
+ if (file.isDirectory()) {
+ throw new IOException("File '" + file + "' exists but is a directory");
+ } else if (!file.canRead()) {
+ throw new IOException("File '" + file + "' cannot be read");
+ } else {
+ return new FileInputStream(file);
+ }
+ } else {
+ throw new FileNotFoundException("File '" + file + "' does not exist");
+ }
+ }
+
+ public static byte[] toByteArray(InputStream input, long size) throws IOException {
+ if (size > 2147483647L) {
+ throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + size);
+ } else {
+ return toByteArray(input, (int) size);
+ }
+ }
+
+ public static byte[] toByteArray(InputStream input, int size) throws IOException {
+ if(size < 0) {
+ throw new IllegalArgumentException("Size must be equal or greater than zero: " + size);
+ } else if(size == 0) {
+ return new byte[0];
+ } else {
+ byte[] data = new byte[size];
+
+ int offset;
+ int read;
+ for(offset = 0; offset < size && (read = input.read(data, offset, size - offset)) != -1; offset += read) {
+ ;
+ }
+
+ if(offset != size) {
+ throw new IOException("Unexpected read size. current: " + offset + ", expected: " + size);
+ } else {
+ return data;
+ }
+ }
+ }
+
+ public static byte[] toByteArray(InputStream input) throws IOException {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Throwable var2 = null;
+
+ byte[] var3;
+ try {
+ copy((InputStream) input, (OutputStream) output);
+ var3 = output.toByteArray();
+ } catch (Throwable var12) {
+ var2 = var12;
+ throw var12;
+ } finally {
+ if (output != null) {
+ if (var2 != null) {
+ try {
+ output.close();
+ } catch (Throwable var11) {
+ var2.addSuppressed(var11);
+ }
+ } else {
+ output.close();
+ }
+ }
+
+ }
+
+ return var3;
+ }
+
+ public static int copy(InputStream input, OutputStream output) throws IOException {
+ long count = copyLarge(input, output);
+ return count > 2147483647L ? -1 : (int) count;
+ }
+
+
+ public static long copyLarge(InputStream input, OutputStream output) throws IOException {
+ return copy(input, output, 4096);
+ }
+
+ public static long copy(InputStream input, OutputStream output, int bufferSize) throws IOException {
+ return copyLarge(input, output, new byte[bufferSize]);
+ }
+
+ public static long copyLarge(InputStream input, OutputStream output, byte[] buffer) throws IOException {
+ long count;
+ int n;
+ for (count = 0L; -1 != (n = input.read(buffer)); count += (long) n) {
+ output.write(buffer, 0, n);
+ }
+
+ return count;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/IDgenerator.java b/src/main/java/xyz/wbsite/frame/utils/IDgenerator.java
new file mode 100644
index 0000000..b14dd36
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/IDgenerator.java
@@ -0,0 +1,75 @@
+package xyz.wbsite.frame.utils;
+
+import java.util.UUID;
+
+/**
+ * IDgenerator - ID生成器
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class IDgenerator {
+
+ private static long workerId = 1L;
+ private static long datacenterId = 1L;
+ private static long sequence = 0L;
+ // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
+ private static long twepoch = 1531130104852L;
+ // 机器标识位数
+ private static long workerIdBits = 2L;//分布应用可设置为5,这里减少占位增加可支持时间
+ // 数据中心标识位数
+ private static long datacenterIdBits = 2L;//分布应用可设置为5,这里减少占位增加可支持时间
+ // 机器ID最大值
+ private static long maxWorkerId = -1L ^ (-1L << workerIdBits);
+ // 数据中心ID最大值
+ private static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
+ // 毫秒内自增位
+ private static long sequenceBits = 12L;
+ // 机器ID偏左移12位
+ private static long workerIdShift = sequenceBits;
+ // 数据中心ID左移17位
+ private static long datacenterIdShift = sequenceBits + workerIdBits;
+ // 时间毫秒左移22位
+ private static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+ private static long sequenceMask = -1L ^ (-1L << sequenceBits);
+ // 上次生产id时间戳
+ private static long lastTimestamp = -1L;
+
+ public static synchronized long nextId() {
+ long timestamp = timeGen();
+
+ if (timestamp < lastTimestamp) {
+ throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+ }
+
+ if (lastTimestamp == timestamp) {
+ sequence = (sequence + 1) & sequenceMask;
+ if (sequence == 0) {
+ timestamp = tilNextMillis(lastTimestamp);
+ }
+ } else {
+ sequence = 0L;
+ }
+
+ lastTimestamp = timestamp;
+
+ return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
+ }
+
+ protected static long tilNextMillis(long lastTimestamp) {
+ long timestamp = timeGen();
+ while (timestamp <= lastTimestamp) {
+ timestamp = timeGen();
+ }
+ return timestamp;
+ }
+
+ protected static long timeGen() {
+ return System.currentTimeMillis();
+ }
+
+ public static String nextUUID() {
+ return UUID.randomUUID().toString();
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/LogUtil.java b/src/main/java/xyz/wbsite/frame/utils/LogUtil.java
new file mode 100644
index 0000000..434d1dc
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/LogUtil.java
@@ -0,0 +1,70 @@
+package xyz.wbsite.frame.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * LogUtil - 日志记录工具类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class LogUtil {
+
+ //定义一个全局的记录器,通过LoggerFactory获取
+ private final static Logger logger = LoggerFactory.getLogger(LogUtil.class);
+
+ /**
+ * 输出info日志
+ * @param context 日志内容
+ */
+ public static void i(String context){
+ logger.info(context);
+ }
+
+ /**
+ * 输出debug日志
+ * @param context 日志内容
+ */
+ public static void d(String context){
+ logger.debug(context);
+ }
+
+ /**
+ * 输出warn日志
+ * @param context 日志内容
+ */
+ public static void w(String context){
+ logger.warn(context);
+ }
+
+ /**
+ * 输出error日志
+ * @param context 日志内容
+ */
+ public static void e(String context){
+ logger.error(context);
+ }
+
+ /**
+ * 获取异常详细堆栈信息
+ */
+ public static void dumpException(Throwable e){
+ StringBuffer msg = new StringBuffer("null");
+ if (e != null) {
+ msg = new StringBuffer("");
+ String message = e.toString();
+ int length = e.getStackTrace().length;
+ if (length > 0) {
+ msg.append(message).append("\n");
+ for (int i = 0; i < length; i++) {
+ msg.append("\t").append(e.getStackTrace()[i]).append("\n");
+ }
+ } else {
+ msg.append(message);
+ }
+ }
+ logger.error(msg.toString());
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/MD5Util.java b/src/main/java/xyz/wbsite/frame/utils/MD5Util.java
new file mode 100644
index 0000000..db3831f
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/MD5Util.java
@@ -0,0 +1,91 @@
+package xyz.wbsite.frame.utils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * MD5Util - MD5工具类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class MD5Util {
+
+ /**
+ * 生成加密密码
+ *
+ * @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);
+ } 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);
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ /**
+ * @param bytes 信息摘要字节数组
+ * @return Hex字符串
+ */
+ 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();
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/MapperUtil.java b/src/main/java/xyz/wbsite/frame/utils/MapperUtil.java
new file mode 100644
index 0000000..215c500
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/MapperUtil.java
@@ -0,0 +1,145 @@
+package xyz.wbsite.frame.utils;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.TreeNode;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.*;
+import org.dozer.DozerBeanMapper;
+import org.dozer.Mapper;
+import xyz.wbsite.frame.auth.LocalData;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+/**
+ * MapUtil - 映射转化工具类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class MapperUtil {
+ private static ObjectMapper om;
+ private static Mapper mapper;
+
+ static {
+ 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();
+ }
+
+ public static TreeNode toTree(String json) {
+ try {
+ return om.readTree(json);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return om.createObjectNode();
+ }
+ }
+
+ public static TreeNode toTree(Object json) {
+ return om.valueToTree(json);
+ }
+
+ public static String toJson(Object object) {
+ return toJson(object, false);
+ }
+
+ public static String toJson(Object object, boolean pretty) {
+ try {
+ if (pretty) {
+ return om.writerWithDefaultPrettyPrinter().writeValueAsString(object);
+ } else {
+ return om.writeValueAsString(object);
+ }
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ return "{}";
+ }
+ }
+
+ public static String toJson(JsonNode jsonNode) {
+ return jsonNode.asText();
+ }
+
+ public static T toJava(String json, Class cls) {
+ try {
+ if (json == null || "".equals(json)) {
+ return cls.newInstance();
+ }
+ return om.readValue(json, cls);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static T toJava(TreeNode treeNode, Class cls) {
+ try {
+ return om.treeToValue(treeNode, cls);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static T toJava(String json, TypeReference valueTypeRef) {
+ try {
+ return om.readValue(json, valueTypeRef);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static List toJavaList(String json, TypeReference> reference) {
+ try {
+ return om.readValue(json, reference);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static List toJavaList(InputStream json, TypeReference> reference) {
+ try {
+ return om.readValue(json, reference);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static T map(Object o, Class aClass) {
+ return mapper.map(o, aClass);
+ }
+
+ public static void map(Object o, Object o1) {
+ mapper.map(o, o1);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/Message.java b/src/main/java/xyz/wbsite/frame/utils/Message.java
new file mode 100644
index 0000000..8be65c7
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/Message.java
@@ -0,0 +1,20 @@
+package xyz.wbsite.frame.utils;
+
+/**
+ * Message - 基本消息类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class Message {
+ public static final String ERROR_500 = "服务器走了下神,稍后再试一次";
+ public static final String NOT_EXIST_METHOD = "调用的方法不存在";
+
+ public static String CREATE_FAILURE = "创建失败,请刷新后重新尝试";
+ public static String DELETE_FAILURE = "删除失败,请刷新后重新尝试";
+ public static String UPDATE_FAILURE = "更新失败,请刷新后重新尝试";
+ public static String FIND_FAILURE = "查询失败,请刷新后重新尝试";
+ public static String GET_FAILURE = "未获取相应内容";
+ public static String INSERT_DUPLICATE = "已经存在相同数据,返回列表页面确认";
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/ProcessUtil.java b/src/main/java/xyz/wbsite/frame/utils/ProcessUtil.java
new file mode 100644
index 0000000..b282322
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/ProcessUtil.java
@@ -0,0 +1,117 @@
+package xyz.wbsite.frame.utils;
+
+import java.awt.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * 程序操作工具
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class ProcessUtil {
+ /**
+ * 启动windows系统下的exe文件
+ * @param path 可执行exe文件路径
+ */
+ public static void execExe(String path) {
+ Runtime rn = Runtime.getRuntime();
+ Process p = null;
+ try {
+ p = rn.exec(path);
+ } catch (Exception e) {
+ System.out.println("Error exec!");
+ }
+ }
+
+ /**
+ * 执行windows批处理文件路
+ * @param path 可执行批处理文件路径
+ */
+ public static void execBat(String path) {
+ Runtime rn = Runtime.getRuntime();
+ Process p = null;
+ try {
+ p = rn.exec(path);
+ } catch (Exception e) {
+ System.out.println("Error exec!");
+ }
+ }
+
+ /**
+ * 执行windows cmd命令
+ * @param command cmd命令
+ */
+ public static String execCmd(String command) {
+ return exec("cmd /c " + command);
+ }
+
+
+ /**
+ * 执行运行环境命令
+ * @param command cmd命令
+ */
+ public static String exec(String command) {
+ StringBuilder build = new StringBuilder();
+ Runtime runtime = Runtime.getRuntime();
+ Process process = null;
+ try {
+ process = runtime.exec(command);
+ BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
+ String line = null;
+ while ((line = br.readLine()) != null) {
+ build.append(line);
+ }
+ process.destroy();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return build.toString();
+ }
+
+ /**
+ * @throws IOException
+ * @desc 杀死进程
+ * @author zp
+ * @date 2018-3-29
+ */
+ public static void killProc(String processName) throws IOException {
+ if (processName != null && !"".equals(processName)) {
+ execCmd("taskkill /F /IM " + processName);
+ }
+ }
+
+ /**
+ * @desc 判断进程是否开启
+ * @author zp
+ * @date 2018-3-29
+ */
+ public static boolean findProcess(String processName) {
+ BufferedReader bufferedReader = null;
+ try {
+ Process proc = Runtime.getRuntime().exec("tasklist -fi " + '"' + "imagename eq " + processName + '"');
+ bufferedReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+ String line = null;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains(processName)) {
+ return true;
+ }
+ }
+ return false;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return false;
+ } finally {
+ if (bufferedReader != null) {
+ try {
+ bufferedReader.close();
+ } catch (Exception ex) {
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/RSAUtil.java b/src/main/java/xyz/wbsite/frame/utils/RSAUtil.java
new file mode 100644
index 0000000..daf49a3
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/RSAUtil.java
@@ -0,0 +1,308 @@
+package xyz.wbsite.frame.utils;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
+/**
+ * RSAUtil - RSA工具类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class RSAUtil {
+
+ private static String cryptPublicKeyBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTrwfsrJjCF+pP4S3A/wrD4U1txg53EuBC1mPt" +
+ "3vGXvSK2U0YNRVR3Q65ooHnPKmk4LwI8v+7+ATTxUg3qkuRiDuzBa5zLkYKM50LOgEWSdOKzbnbx" +
+ "a5FnE7IXawNt1p8+MVN1TTI7J/fZy6g1x0WBy1odE5Osru4WfZNOqQtjHwIDAQAB";
+ private static String cryptPrivateKeyBase64 = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJOvB+ysmMIX6k/hLcD/CsPhTW3G" +
+ "DncS4ELWY+3e8Ze9IrZTRg1FVHdDrmigec8qaTgvAjy/7v4BNPFSDeqS5GIO7MFrnMuRgoznQs6A" +
+ "RZJ04rNudvFrkWcTshdrA23Wnz4xU3VNMjsn99nLqDXHRYHLWh0Tk6yu7hZ9k06pC2MfAgMBAAEC" +
+ "gYBjLRjKRMI1HfBZgmPChsPI9YWU4XuXVVLLL8Rd2uktOHOWM2gIw3VMvmPimVoT2GxesZr0BwTN" +
+ "CSxvnuX/kHPTqtsIu1r5Iup3mGbvlj3sn8RvG0yvUDglDN7QVDqqN7XWvHJSBVfBzDXeExA/WGnE" +
+ "6BOocNT9qkqA/UWNbCXGKQJBAN0Fd/P2D6EvCd2RztHhzVE6V8s/LwOTDnGn/YhdMpddy9TwZpBi" +
+ "r7I6lzcLWQ1HfDUive3t+DGXqPqr/4FfkG0CQQCrDlZKf216QrXOmJ70LQSbflgvGYU+b6kLFyEh" +
+ "+15HcIBfKUQCU+XUK4UzLMQDYxdngTNMNyq4AQ9Sh0tUTUI7AkEAtkq9XayzxWhLhcCtyTOoqPcq" +
+ "1Aqf1x3iCuHYXTEo+ek1pcJFhY6vhJuIfrDQWQB9tEGcTvI4A4cnquBTkzvjnQJAYid58ImqYmuB" +
+ "M6l0HJzwdeFL7MryIF+mWozNIFjDQq8VmoVtVwCZcuP+LN1VJLRpq6UBsIw/YRKKnkqwORGUHQJA" +
+ "UuR0G/3Hai+vKDA14tIYIH6C4zNmbULxAEuQVh9thfafWNmiDcifApvkxQ2ewXwEGeJtz44zv6iY" +
+ "3f3yq+a2OQ==";
+
+ private static String signPublicKeyBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTrwfsrJjCF+pP4S3A/wrD4U1txg53EuBC1mPt" +
+ "3vGXvSK2U0YNRVR3Q65ooHnPKmk4LwI8v+7+ATTxUg3qkuRiDuzBa5zLkYKM50LOgEWSdOKzbnbx" +
+ "a5FnE7IXawNt1p8+MVN1TTI7J/fZy6g1x0WBy1odE5Osru4WfZNOqQtjHwIDAQAB";
+ private static String signPrivateKeyBase64 = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJOvB+ysmMIX6k/hLcD/CsPhTW3G" +
+ "DncS4ELWY+3e8Ze9IrZTRg1FVHdDrmigec8qaTgvAjy/7v4BNPFSDeqS5GIO7MFrnMuRgoznQs6A" +
+ "RZJ04rNudvFrkWcTshdrA23Wnz4xU3VNMjsn99nLqDXHRYHLWh0Tk6yu7hZ9k06pC2MfAgMBAAEC" +
+ "gYBjLRjKRMI1HfBZgmPChsPI9YWU4XuXVVLLL8Rd2uktOHOWM2gIw3VMvmPimVoT2GxesZr0BwTN" +
+ "CSxvnuX/kHPTqtsIu1r5Iup3mGbvlj3sn8RvG0yvUDglDN7QVDqqN7XWvHJSBVfBzDXeExA/WGnE" +
+ "6BOocNT9qkqA/UWNbCXGKQJBAN0Fd/P2D6EvCd2RztHhzVE6V8s/LwOTDnGn/YhdMpddy9TwZpBi" +
+ "r7I6lzcLWQ1HfDUive3t+DGXqPqr/4FfkG0CQQCrDlZKf216QrXOmJ70LQSbflgvGYU+b6kLFyEh" +
+ "+15HcIBfKUQCU+XUK4UzLMQDYxdngTNMNyq4AQ9Sh0tUTUI7AkEAtkq9XayzxWhLhcCtyTOoqPcq" +
+ "1Aqf1x3iCuHYXTEo+ek1pcJFhY6vhJuIfrDQWQB9tEGcTvI4A4cnquBTkzvjnQJAYid58ImqYmuB" +
+ "M6l0HJzwdeFL7MryIF+mWozNIFjDQq8VmoVtVwCZcuP+LN1VJLRpq6UBsIw/YRKKnkqwORGUHQJA" +
+ "UuR0G/3Hai+vKDA14tIYIH6C4zNmbULxAEuQVh9thfafWNmiDcifApvkxQ2ewXwEGeJtz44zv6iY" +
+ "3f3yq+a2OQ==";
+
+ /**
+ * 创建密钥和私钥
+ */
+ public static void createKey() {
+ try {
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(1024);
+ KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+ //公钥
+ RSAPublicKey aPublic = (RSAPublicKey) keyPair.getPublic();
+ //私钥
+ RSAPrivateKey aPrivate = (RSAPrivateKey) keyPair.getPrivate();
+ //把密钥对象对应的字节转为Base64字符存储
+ System.err.println("publicKeyBase64-->" + Base64Util.encodeToString(aPublic.getEncoded()));
+ System.err.println("privateKeyBase64-->" + Base64Util.encodeToString(aPrivate.getEncoded()));
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String encrypt2Base64(byte[] data) {
+ byte[] encrypt = encrypt(data);
+ return Base64Util.encodeToString(encrypt);
+ }
+
+ public static byte[] encrypt(String data) {
+ return encrypt(data.getBytes());
+ }
+
+ /**
+ * 加密
+ *
+ * @param data 待加密数据
+ */
+ public static byte[] encrypt(byte[] data) {
+ try {
+ //生成公钥对象
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64Util.decode(cryptPublicKeyBase64));
+ PublicKey aPublic = keyFactory.generatePublic(x509EncodedKeySpec);
+
+ //分段加密开始
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.ENCRYPT_MODE, aPublic);
+ int offset = 0;
+ while (offset < data.length) {
+ byte[] bytes = rsa.doFinal(Arrays.copyOfRange(data, offset, Math.min(offset + 117, data.length)));
+ bs.write(bytes);
+ offset += 117;
+ }
+ return bs.toByteArray();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 加密
+ *
+ * @param data 待加密明文
+ */
+ public static byte[] encrypt(String data, PublicKey aPublic) {
+ try {
+ if (aPublic == null) {
+ System.err.println("PublicKey can not be null");
+ return null;
+ }
+
+ //分段加密开始
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.ENCRYPT_MODE, aPublic);
+ int offset = 0;
+ byte[] b = data.getBytes();
+ while (offset < b.length) {
+ byte[] bytes = rsa.doFinal(Arrays.copyOfRange(b, offset, Math.min(offset + 117, b.length)));
+ bs.write(bytes);
+ offset += 117;
+ }
+ return bs.toByteArray();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * @param base64String base64编码字符串
+ * @return
+ */
+ public static byte[] decrypt(String base64String) {
+ return decrypt(Base64Util.decode(base64String));
+ }
+
+ public static String decrypt2String(String base64String) {
+ byte[] decrypt = decrypt(Base64Util.decode(base64String));
+ try {
+ return new String(decrypt, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 解密
+ *
+ * @param data 已加密字节
+ */
+ public static byte[] decrypt(byte[] data) {
+ try {
+ //生成私钥对象
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64Util.decode(cryptPrivateKeyBase64));
+ PrivateKey aPrivate = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
+
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.DECRYPT_MODE, aPrivate);
+ //获得密文字节
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ int offset = 0;
+ while (offset < data.length) {
+ byte[] bytes = rsa.doFinal(Arrays.copyOfRange(data, offset, Math.min(offset + 128, data.length)));
+ bs.write(bytes);
+ offset += 128;
+ }
+ return bs.toByteArray();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 解密
+ *
+ * @param data 已加密字节
+ * @param aPrivate 公钥
+ * @return 解密后的字节
+ */
+ public static byte[] decrypt(byte[] data, PublicKey aPrivate) {
+ try {
+ if (aPrivate == null) {
+ System.err.println("PublicKey can not be null");
+ return null;
+ }
+
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.DECRYPT_MODE, aPrivate);
+ //获得密文字节
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ int offset = 0;
+ while (offset < data.length) {
+ byte[] bytes = rsa.doFinal(Arrays.copyOfRange(data, offset, Math.min(offset + 128, data.length)));
+ bs.write(bytes);
+ offset += 128;
+ }
+ return bs.toByteArray();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static String sign2Base64(byte[] data) {
+ return sign2Base64(data, signPrivateKeyBase64);
+ }
+
+ public static String sign2Base64(byte[] data, String privateKey) {
+ byte[] sign = sign(data, privateKey);
+ return Base64Util.encodeToString(sign);
+ }
+
+ /**
+ * RSA签名
+ *
+ * @param data 待签名数据
+ * @param privateKey 私钥
+ * @return 签名字节数组
+ */
+ public static byte[] sign(byte[] data, String privateKey) {
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Util.decode(privateKey));
+ PrivateKey aPrivate = keyFactory.generatePrivate(priPKCS8);
+
+ Signature signature = Signature.getInstance("SHA1WithRSA");
+
+ signature.initSign(aPrivate);
+ signature.update(data);
+ return signature.sign();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * RSA验签名检查
+ *
+ * @param data 待签名数据
+ * @param sign base64 签名字符串
+ * @param publicKey 公钥
+ * @return 布尔值
+ */
+ public static boolean doCheck(byte[] data, String sign, String publicKey) {
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ byte[] encodedKey = Base64Util.decode(publicKey);
+ PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
+ Signature signature = Signature.getInstance("SHA1WithRSA");
+ signature.initVerify(pubKey);
+ signature.update(data);
+ return signature.verify(Base64Util.decode(sign));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ public static boolean doCheck(byte[] data, String sign) {
+ return doCheck(data, sign, signPublicKeyBase64);
+ }
+
+ public static PublicKey parsePublicKey(String cryptPublicKeyBase64) {
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64Util.decode(cryptPublicKeyBase64));
+ return keyFactory.generatePublic(x509EncodedKeySpec);
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (InvalidKeySpecException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static PrivateKey parsePrivateKey(String cryptPrivateKeyBase64) {
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Util.decode(cryptPrivateKeyBase64));
+ return keyFactory.generatePrivate(priPKCS8);
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (InvalidKeySpecException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/RequestUtil.java b/src/main/java/xyz/wbsite/frame/utils/RequestUtil.java
new file mode 100644
index 0000000..a9fe557
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/RequestUtil.java
@@ -0,0 +1,79 @@
+package xyz.wbsite.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 "";
+ }
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/ResourceUtil.java b/src/main/java/xyz/wbsite/frame/utils/ResourceUtil.java
new file mode 100644
index 0000000..eab3c72
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/ResourceUtil.java
@@ -0,0 +1,144 @@
+package xyz.wbsite.frame.utils;
+
+import org.springframework.boot.system.ApplicationHome;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.ResourceUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+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 {
+
+ /**
+ * 获取资源目录下所有文件名 如: /modules/dir/
+ *
+ * @param resourcePath 路径
+ * @return
+ */
+ public static List getResourceFiles(String resourcePath) {
+ List result = new ArrayList<>();
+ File applicationHome = getApplicationHome();
+ if (applicationHome.getAbsolutePath().endsWith(".jar")) {
+ try {
+ Pattern pattern = Pattern.compile(".*" + resourcePath + "(.+\\..+)");
+ JarFile jarFile = new JarFile(applicationHome);
+ Enumeration entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry jarEntry = entries.nextElement();
+ String name = jarEntry.getName();
+
+ if (name.matches(".*" + resourcePath + "(.+\\..+)")) {
+ Matcher matcher = pattern.matcher(name);
+ if (matcher.find()) result.add(matcher.group(1));
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ try {
+ ClassPathResource cpr = new ClassPathResource(resourcePath);
+ File in = cpr.getFile();
+ for (File file : in.listFiles()) {
+ result.add(file.getName());
+ }
+ return result;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * 获取当前运行jar文件
+ *
+ * @return jar路径
+ */
+ public static File getApplicationHome() {
+ ApplicationHome home = new ApplicationHome(ResourceUtil.class);
+ return home.getSource();
+ }
+
+ /**
+ * 获取resource下文件
+ *
+ * @return 文件路径
+ */
+ public static InputStream getResourceInput(String resource) {
+ try {
+ ClassPathResource classPathResource = new ClassPathResource(resource);
+ return classPathResource.getInputStream();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * 复制jar下的资源文件到指定文件
+ *
+ * @return 成功或失败情况
+ */
+ public static boolean copyResource2File(String resource, File file) {
+ InputStream resourceInput = getResourceInput(resource);
+ FileOutputStream fileOutputStream = null;
+ try {
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ fileOutputStream = new FileOutputStream(file);
+ FileUtil.copy(resourceInput, fileOutputStream);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ } finally {
+ try {
+ if (fileOutputStream != null) fileOutputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 获取资源的的字节数组
+ *
+ * @return 字节数组
+ */
+ public static byte[] getResourceBytes(String resource) {
+ InputStream is = null;
+ byte[] result = null;
+ try {
+ is = getResourceInput(resource);
+ result = new byte[is.available()];
+ is.read(result);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (is != null) is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/ResponseUtil.java b/src/main/java/xyz/wbsite/frame/utils/ResponseUtil.java
new file mode 100644
index 0000000..48d02e7
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/ResponseUtil.java
@@ -0,0 +1,42 @@
+package xyz.wbsite.frame.utils;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import xyz.wbsite.frame.excel.WExcel;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+/**
+ * ResponseUtil
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class ResponseUtil {
+
+ /**
+ * 包装ResponseEntity
+ *
+ * @param bytes 字节数组
+ * @param fileName 文件名
+ * @return
+ */
+ public static ResponseEntity apply(byte[] bytes, String fileName) {
+ try {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+ headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, "utf-8"));
+ return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ }
+
+ public static ResponseEntity apply(WExcel sheet) {
+ return apply(sheet.getBytes(), sheet.getName() + ".xlsx");
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/StringUtil.java b/src/main/java/xyz/wbsite/frame/utils/StringUtil.java
new file mode 100644
index 0000000..767dbe8
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/StringUtil.java
@@ -0,0 +1,87 @@
+package xyz.wbsite.frame.utils;
+
+public class StringUtil {
+
+ public static int getByteLength(String str) {
+ int length = str.replaceAll("[^\\x00-\\xff]", "**").length();
+ return length;
+ }
+
+ public static String upperFirstWord(String str) {
+ String temp = str.substring(0, 1);
+ return temp.toUpperCase() + str.substring(1);
+ }
+
+ public static boolean isEmpty(String value) {
+ int strLen;
+ if (value == null || (strLen = value.length()) == 0) {
+ return true;
+ }
+ for (int i = 0; i < strLen; i++) {
+ if ((Character.isWhitespace(value.charAt(i)) == false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public static boolean isNotEmpty(String value) {
+ return !isEmpty(value);
+ }
+
+
+ /**
+ * 检查对象是否为数字型字符串,包含负数开头的。
+ */
+ public static boolean isNumeric(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ char[] chars = obj.toString().toCharArray();
+ int length = chars.length;
+ if (length < 1)
+ return false;
+
+ int i = 0;
+ if (length > 1 && chars[0] == '-')
+ i = 1;
+
+ for (; i < length; i++) {
+ if (!Character.isDigit(chars[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 把通用字符编码的字符串转化为汉字编码。
+ */
+ public static String unicodeToChinese(String unicode) {
+ StringBuilder out = new StringBuilder();
+ if (!isEmpty(unicode)) {
+ for (int i = 0; i < unicode.length(); i++) {
+ out.append(unicode.charAt(i));
+ }
+ }
+ return out.toString();
+ }
+
+
+ public static String toUnderlineStyle(String name) {
+ StringBuilder newName = new StringBuilder();
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ if (Character.isUpperCase(c)) {
+ if (i > 0) {
+ newName.append("_");
+ }
+ newName.append(Character.toLowerCase(c));
+ } else {
+ newName.append(c);
+ }
+ }
+ return newName.toString();
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/UrlUtil.java b/src/main/java/xyz/wbsite/frame/utils/UrlUtil.java
new file mode 100644
index 0000000..73e2944
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/UrlUtil.java
@@ -0,0 +1,41 @@
+package xyz.wbsite.frame.utils;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Locale;
+
+/**
+ * Url工具类
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+@Component
+public class UrlUtil {
+
+ public String getUrl(String url) {
+ if (url == null) {
+ return "";
+ }
+
+ if (!url.startsWith("/")) {
+ return "/" + url;
+ }
+
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ // 协议
+ String scheme = request.getScheme();
+ // 域名
+ String serverName = request.getServerName();
+ // 端口
+ int serverPort = request.getServerPort();
+ // 上下文路径
+ String context = request.getContextPath();
+
+ return String.format(Locale.CHINA, "%s://%s:%d%s%s", scheme, serverName, serverPort, context, url);
+ }
+}
diff --git a/src/main/java/xyz/wbsite/frame/utils/ValidationUtil.java b/src/main/java/xyz/wbsite/frame/utils/ValidationUtil.java
new file mode 100644
index 0000000..78b5d04
--- /dev/null
+++ b/src/main/java/xyz/wbsite/frame/utils/ValidationUtil.java
@@ -0,0 +1,72 @@
+package xyz.wbsite.frame.utils;
+
+import xyz.wbsite.frame.base.BaseRequest;
+import xyz.wbsite.frame.base.BaseResponse;
+import xyz.wbsite.frame.base.ErrorType;
+
+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;
+
+/**
+ * 验证工具类。提供一些通用简单的数据验证功能
+ *
+ * @author wangbing
+ * @version 0.0.1
+ * @since 2017-01-01
+ */
+public class ValidationUtil {
+
+ private static ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+
+ public static T validate(BaseRequest req, T response) {
+
+ if (req == null) {
+ response.addError(ErrorType.EXPECTATION_NULL, "请求对象不能为空");
+ return response;
+ }
+
+ try {
+ Validator validator = factory.getValidator();
+
+ Set> constraintViolations = validator.validate(req);
+
+ if (constraintViolations.size() > 0) {
+ for (ConstraintViolation violation : constraintViolations) {
+ response.addError(ErrorType.INVALID_PARAMETER, violation.getMessage());
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ LogUtil.dumpException(e);
+ response.addError(ErrorType.BUSINESS_ERROR, e.getMessage());
+ }
+ return response;
+ }
+
+ public static List validate(Object req) {
+ List validResult = new ArrayList<>();
+ if (req == null) {
+ validResult.add("当前数据为空");
+ return validResult;
+ }
+
+ try {
+ Validator validator = factory.getValidator();
+ Set> constraintViolations = validator.validate(req);
+ if (constraintViolations.size() > 0) {
+ for (ConstraintViolation