You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

338 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package ${basePackage}.action;
import ${basePackage}.frame.base.*;
import ${basePackage}.frame.auth.LocalData;
import ${basePackage}.config.ActionConfig;
import ${basePackage}.frame.utils.MapperUtil;
import org.springframework.beans.BeansException;
import org.apache.commons.io.FileUtils;
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)}
* <p>
* 说明Request命名规则驼峰式命名
* Api#Example#Request ==> 目标#动作#Request
*
* @author author
* @version 0.0.1
* @since 2019-06-16
*/
@Controller
@ControllerAdvice
public class GlobalController implements ErrorController {
@Value("${r'${web.welcome.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("<a>").append(message).append("</a><br>");
for (int i = 0; i < length; i++) {
msg.append("<a>").append(exception.getStackTrace()[i]).append("</a><br>");
}
} 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 {
Screen screenExec = LocalData.getApplicationContext().getBean(ActionConfig.SCREEN_PREFIX + action, 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 {
Object ajax = LocalData.getApplicationContext().getBean(ActionConfig.AJAX_PREFIX + module + "." + target);
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<byte[]> 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<byte[]>("test".getBytes(),
headers, HttpStatus.CREATED);
}
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(new File(file)),
headers, HttpStatus.CREATED);
}
private static ConcurrentHashMap<String, SseEmitter> 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);
}
}
}
}

Powered by TurnKey Linux.