package xyz.wbsite.dbtool.web.action; import org.apache.tomcat.util.http.fileupload.FileUtils; import xyz.wbsite.dbtool.web.config.ActionConfig; import xyz.wbsite.dbtool.web.frame.base.*; import xyz.wbsite.dbtool.web.frame.auth.LocalData; import xyz.wbsite.dbtool.web.frame.utils.FileUtil; import xyz.wbsite.dbtool.web.frame.utils.MapperUtil; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; 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.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.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 java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; 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)} * 全局异常捕捉{@link GlobalController#exceptionHandler(HttpServletRequest, HttpServletResponse, Model, Exception)} * 全局上传接口{@link GlobalController#upload(HttpServletRequest)} * 全局下载接口{@link GlobalController#download(String)} * 全局消息订阅{@link GlobalController#sse(String)} *
* 说明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;
@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:
try {
response.sendRedirect("/login.htm");
} 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.setStatus(HttpServletResponse.SC_NOT_FOUND);
return error(request, response);
}
// 尝试执行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) {
return error(request, response);
}
} 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("/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("/ajax/{module}/{target}/{method}")
@ResponseBody
public BaseResponse ajax(@PathVariable String module, @PathVariable String target, @PathVariable String method, @RequestBody String param) {
BaseResponse baseResponse = null;
try {
String beanClassName = (ActionConfig.AJAX_PREFIX + module + "/" + target).toLowerCase();
Object ajax = LocalData.getApplicationContext().getBean(beanClassName);
Class ajaxClass = ajax.getClass();
Method methodC = ajaxClass.getMethod(method, String.class);
Object invoke = methodC.invoke(ajax, param);
if (invoke instanceof BaseResponse) {
baseResponse = (BaseResponse) invoke;
} else {
baseResponse = new BaseResponse();
baseResponse.addError(ErrorType.BUSINESS_ERROR, "方法返回值错误!");
}
} catch (BeansException e) {
baseResponse = new BaseResponse();
baseResponse.addError(ErrorType.BUSINESS_ERROR, "未找到对应的目标!");
} catch (NoSuchMethodException e) {
baseResponse = new BaseResponse();
baseResponse.addError(ErrorType.BUSINESS_ERROR, "未找到对应的方法!");
} catch (IllegalAccessException e) {
baseResponse = new BaseResponse();
baseResponse.addError(ErrorType.BUSINESS_ERROR, "方法执必须公开!");
} catch (InvocationTargetException e) {
baseResponse = new BaseResponse();
baseResponse.addError(ErrorType.BUSINESS_ERROR, "方法执行错误!");
}
return baseResponse;
}
@RequestMapping("/download")
@ResponseBody
public ResponseEntity