PageRenderTime 2838ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/211AuthcenterProject/authcenter-web/src/main/java/com/fdhay/authcenter/web/controller/base/BaseController.java

http://java-hiking.googlecode.com/
Java | 420 lines | 267 code | 46 blank | 107 comment | 18 complexity | 6ed9232d30cfcdfb5027b777c4c97a0e MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. package com.fdhay.authcenter.web.controller.base;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.StringWriter;
  5. import java.io.UnsupportedEncodingException;
  6. import java.net.URLEncoder;
  7. import java.util.ArrayList;
  8. import java.util.HashMap;
  9. import java.util.List;
  10. import java.util.Map;
  11. import java.util.UUID;
  12. import javax.annotation.Resource;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpServletResponse;
  15. import org.apache.commons.lang.StringUtils;
  16. import org.apache.commons.logging.Log;
  17. import org.apache.commons.logging.LogFactory;
  18. import org.springframework.stereotype.Controller;
  19. import org.springframework.validation.ObjectError;
  20. import org.springframework.web.bind.annotation.ExceptionHandler;
  21. import org.springframework.web.servlet.ModelAndView;
  22. import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
  23. import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
  24. import com.alibaba.fastjson.JSON;
  25. import com.fdhay.authcenter.common.Constants;
  26. import com.fdhay.authcenter.common.util.FileUtils;
  27. import com.fdhay.authcenter.domain.User;
  28. import com.fdhay.authcenter.service.SessionService;
  29. import com.fdhay.authcenter.web.controller.base.helper.SessionHelper;
  30. import com.fdhay.authcenter.web.controller.base.interceptor.ControllerContext;
  31. import freemarker.template.Configuration;
  32. import freemarker.template.Template;
  33. @Controller
  34. public class BaseController {
  35. protected Log logger = LogFactory.getLog(getClass());
  36. //默认的freemarker配置器
  37. @Resource private FreeMarkerConfigurer freemarkerConfigurer;
  38. @Resource private FreeMarkerViewResolver viewResolver;
  39. @Resource private SessionService sessionService;
  40. protected String CONTEXT_PATH_KEY = "contextPath";
  41. protected String CONTEXT_FULL_PATH_KEY = "contextFullPath";
  42. protected int DEFAULT_HTTP_PORT = 80;
  43. private String VIEW_CONTENT_KEY = "viewContent";
  44. private String DEFAULT_LAYOUT_VIEW_NAME = "common/layout/default-layout";
  45. private String EXCEPTION_VIEW_NAME = "common/exception/exception-message";
  46. private String FREEMARKER_SUFFIX = ".ftl";
  47. private String CONTENT_TYPE_OF_JSON = "text/html; charset=utf-8";//fix IE ajax fileupload issue, so change type from application/json to text/html
  48. private String CONTENT_TYPE_OF_TEXT = "text/plain; charset=utf-8";
  49. private String CONTENT_TYPE_OF_HTML = "text/html; charset=utf-8";
  50. private Map<String, Object> defaultModelMap = new HashMap<String, Object>(1);
  51. private Map<String, Object> modelMap = null;
  52. private List<ObjectError> errorList = null;
  53. private static final String KEY_OF_MODEL_MAP = "modelMap";
  54. private static final String KEY_OF_ERROR_LIST = "errorList";
  55. //自定义的freemarker,用于加载自定义路径下的模板
  56. private Configuration customFreemarkerConfiguration = new Configuration();
  57. @SuppressWarnings("unchecked")
  58. public Map<String, Object> getModelMap() {
  59. modelMap = (Map<String, Object>) ControllerContext.getContext().get(KEY_OF_MODEL_MAP);
  60. if(modelMap == null){
  61. modelMap = new HashMap<String, Object>(1);
  62. ControllerContext.getContext().put(KEY_OF_MODEL_MAP, modelMap);
  63. }
  64. return modelMap;
  65. }
  66. public void setModelMap(Map<String, Object> modelMap) {
  67. this.modelMap = modelMap;
  68. }
  69. @SuppressWarnings("unchecked")
  70. public List<ObjectError> getErrorList() {
  71. errorList = (ArrayList<ObjectError>) ControllerContext.getContext().get(KEY_OF_ERROR_LIST);
  72. if(errorList == null){
  73. errorList = new ArrayList<ObjectError>(1);
  74. ControllerContext.getContext().put(KEY_OF_ERROR_LIST, errorList);
  75. }
  76. return errorList;
  77. }
  78. protected HttpServletRequest getRequest(){
  79. return ControllerContext.getContext().getRequest();
  80. }
  81. protected HttpServletResponse getResponse(){
  82. return ControllerContext.getContext().getResponse();
  83. }
  84. protected User getLoginUser(){
  85. return (User) ControllerContext.getContext().get(Constants.KEY_OF_LOGIN_USER);
  86. }
  87. protected String getLoginUserCookie(){
  88. return (String) ControllerContext.getContext().get(Constants.KEY_OF_LOGIN_USER_COOKIE);
  89. }
  90. /**
  91. * 使用默认layout布局页面展示viewName的内容
  92. * @param viewName - 视图页面的全路径名,不含后缀。
  93. * Eg: "message/message-info", 表示使用页面 /WEB-INF/view/message/message-info.ftl
  94. * @param modelMap - 视图页面需要的变量<key, value>键值对。页面使用Eg:${message!}
  95. * @return
  96. */
  97. public ModelAndView toView(String viewName, Map<String, Object> modelMap){
  98. return this.toViewWithLayout(viewName, getDefaultLayout(), modelMap);
  99. }
  100. /**
  101. * 使用默认layout布局页面展示content的内容
  102. * @param content
  103. * @param modelMap
  104. * @return
  105. */
  106. public ModelAndView toViewOfContent(String content, Map<String, Object> modelMap){
  107. return this.toViewOfContentWithLayout(content, getDefaultLayout(), modelMap);
  108. }
  109. /**
  110. * 获取默认布局页面
  111. * @return
  112. */
  113. protected String getDefaultLayout() {
  114. return DEFAULT_LAYOUT_VIEW_NAME;
  115. }
  116. /**
  117. * 使用layoutPageName布局页面作为布局模板,展示viewName页面生成的内容
  118. * @param viewName- 视图页面的全路径名,不含后缀。
  119. * Eg: "message/message-info", 表示使用页面 /WEB-INF/view/message/message-info.ftl
  120. * @param layoutPageName - 模板布局页面,Eg:"common/layout/myself-layout"
  121. * @param modelMap - 视图页面需要的变量<key, value>键值对。页面使用Eg:${message!}
  122. * @return
  123. */
  124. public ModelAndView toViewWithLayout(String viewName, String layoutPageName, Map<String, Object> modelMap){
  125. Map<String, Object> mergedMap = mergedModelMap(defaultModelMap, modelMap);
  126. //
  127. String resultContent = getContentFromTemplate(viewName, mergedMap);
  128. mergedMap.put(VIEW_CONTENT_KEY, resultContent);
  129. //
  130. ModelAndView mv = new ModelAndView();
  131. mv.setViewName(layoutPageName);
  132. mv.addAllObjects(mergedMap);
  133. logger.info("visit view page ===> " + viewName + FREEMARKER_SUFFIX);
  134. return mv;
  135. }
  136. /**
  137. * 使用layoutPageName布局页面作为布局模板,展示content的内容
  138. * @param content - 在模板中展示的内容
  139. * @param layoutPageName - 模板布局页面,Eg:"common/layout/myself-layout"
  140. * @param modelMap - 视图页面需要的变量<key, value>键值对。页面使用Eg:${message!}
  141. * @return
  142. */
  143. public ModelAndView toViewOfContentWithLayout(String content, String layoutPageName, Map<String, Object> modelMap){
  144. Map<String, Object> mergedMap = mergedModelMap(defaultModelMap, modelMap);
  145. mergedMap.put(VIEW_CONTENT_KEY, content);
  146. //
  147. ModelAndView mv = new ModelAndView();
  148. mv.setViewName(layoutPageName);
  149. mv.addAllObjects(mergedMap);
  150. logger.info("visit view content === ");
  151. return mv;
  152. }
  153. /**
  154. * 从freemarker模板中获得解析后的内容
  155. * @param viewName - 视图页面的全路径名,不含后缀,默认为 .ftl
  156. * <p>
  157. * Eg: "message/message-info", 表示使用页面 /WEB-INF/view/message/message-info.ftl
  158. * </p>
  159. * @param modelMap - 视图页面需要的变量<key, value>键值对。页面使用Eg:${message!}
  160. * @return - 解析后的内容
  161. */
  162. public String getContentFromTemplate(String viewName, Map<String, Object> modelMap) {
  163. return this.processTemplate(freemarkerConfigurer.getConfiguration(), viewName + FREEMARKER_SUFFIX, modelMap);
  164. }
  165. /**
  166. * 从freemarker模板中获得解析后的内容
  167. * @param viewName - 视图页面的全路径名,不含后缀。
  168. * @param viewSuffix - 视图页面的后缀,eg: .json/.ftl
  169. * <p>
  170. * Eg: "message/message-info", ".json" 表示使用页面 /WEB-INF/view/message/message-info.ftl
  171. * </p>
  172. * @param modelMap - 视图页面需要的变量<key, value>键值对。页面使用Eg:${message!}
  173. * @return 解析后的内容
  174. */
  175. public String getContentFromTemplate(String viewName, String viewSuffix, Map<String, Object> modelMap) {
  176. return this.processTemplate(freemarkerConfigurer.getConfiguration(), viewName + viewSuffix, modelMap);
  177. }
  178. /**
  179. * 从指定的目录加载模板,并解析模板返回解析后的内容
  180. * @param templateDir - 指定的目录加载模板
  181. * @param viewNameIncludeSuffix - 视图页面的全路径名,需含后缀,eg: myViewPage.html
  182. * @param modelMap - 视图页面需要的变量<key, value>键值对。页面使用Eg:${message!}
  183. * @return - 解析后的内容
  184. * @throws IOException
  185. */
  186. public String getContentFromTemplateDir(String templateDir, String viewNameIncludeSuffix, Map<String, Object> modelMap) throws IOException {
  187. //设置新的Template load目录
  188. try {
  189. customFreemarkerConfiguration.setDirectoryForTemplateLoading(new File(templateDir));
  190. customFreemarkerConfiguration.setDefaultEncoding(Constants.DEFAULT_CHARSET);
  191. } catch (IOException e1) {
  192. logger.error(e1);
  193. throw e1;
  194. }
  195. FileUtils.checkFileExist(templateDir + "/" + viewNameIncludeSuffix);
  196. String resultContent = processTemplate(customFreemarkerConfiguration, viewNameIncludeSuffix, modelMap);
  197. return resultContent;
  198. }
  199. private String processTemplate(Configuration freemarkerConfiguration, String viewNameIncludeSuffix, Map<String, Object> modelMap) {
  200. StringWriter resultWriter = new StringWriter();
  201. try {
  202. Template template = freemarkerConfiguration.getTemplate(viewNameIncludeSuffix);
  203. template.process(mergedModelMap(defaultModelMap, modelMap), resultWriter);
  204. } catch (Exception e) {
  205. logger.error(e);
  206. throw new RuntimeException(e);
  207. }
  208. return resultWriter.toString();
  209. }
  210. /**
  211. * 不使用layout布局页面,直接把viewName指向的页面内容输出。
  212. * @param viewName
  213. * @param modelMap
  214. * @return
  215. */
  216. public ModelAndView toViewWithoutLayout(String viewName, Map<String, Object> modelMap){
  217. ModelAndView mv = new ModelAndView();
  218. mv.setViewName(viewName);
  219. mv.addAllObjects(mergedModelMap(defaultModelMap, modelMap));
  220. logger.info("visit view page ===> " + viewName + FREEMARKER_SUFFIX);
  221. return mv;
  222. }
  223. /**
  224. * 把参数对象作为json串输出到客户端。
  225. * @param javaObject
  226. */
  227. public ModelAndView toJSON(Object javaObject){
  228. return sendToClient(CONTENT_TYPE_OF_JSON, JSON.toJSONString(javaObject));
  229. }
  230. public ModelAndView toText(String text){
  231. return sendToClient(CONTENT_TYPE_OF_TEXT, text);
  232. }
  233. public ModelAndView toHTML(String html){
  234. return sendToClient(CONTENT_TYPE_OF_HTML, html);
  235. }
  236. /**
  237. * 用于处理异常的
  238. * @return
  239. */
  240. @ExceptionHandler({Exception.class})
  241. public ModelAndView exception(Exception e) {
  242. String errorCode = getRequest().getParameter(Constants.KEY_OF_ERROR_CODE);
  243. String errorMsg = (String) getRequest().getAttribute(Constants.KEY_OF_ERROR_MSG);
  244. logger.error("do ExceptionHandler --> " +
  245. " [errorCode=" + errorCode + "]" +
  246. " [errorMsg=" + errorMsg + "]", e);
  247. //request的attribute中存在的属性底层会加入到model对象中。
  248. getModelMap().put(Constants.KEY_OF_ERROR_CODE, errorCode);
  249. //返回exception试图
  250. return toError(EXCEPTION_VIEW_NAME, getModelMap());
  251. }
  252. public ModelAndView toError(String viewName, Map<String, Object> modelMap){
  253. ModelAndView mv = new ModelAndView();
  254. mv.setViewName(viewName);
  255. mv.addAllObjects(modelMap);
  256. logger.info("visit error page ===> " + viewName + FREEMARKER_SUFFIX);
  257. return mv;
  258. }
  259. public ModelAndView toError(String errorMsg){
  260. return toError(404, errorMsg);
  261. }
  262. public ModelAndView toError(int errorCode, String errorMsg){
  263. try {
  264. getRequest().setAttribute(Constants.KEY_OF_ERROR_MSG, errorMsg);
  265. getResponse().sendError(errorCode, errorMsg);
  266. } catch (IOException e) {
  267. logger.error(e);
  268. }
  269. return null;
  270. }
  271. private ModelAndView sendToClient(String contentType, String content){
  272. logger.debug("send to client content type = " + contentType);
  273. //logger.debug("send to client content = " + content);
  274. HttpServletResponse response = getResponse();
  275. response.setContentType(contentType);
  276. try {
  277. response.getWriter().print(content);
  278. response.flushBuffer();
  279. } catch (IOException e) {
  280. logger.error(e);
  281. }
  282. return null;
  283. }
  284. private Map<String, Object> mergedModelMap(Map<String, Object> defaultModelMap, Map<String, Object> modelMap){
  285. Map<String, Object> mergedModelMap = new HashMap<String, Object>();
  286. //把参数传递过来的modelMap合并到mergedModelMap。
  287. if(defaultModelMap != null){
  288. mergedModelMap.putAll(defaultModelMap);
  289. }
  290. if(modelMap != null){
  291. mergedModelMap.putAll(modelMap);
  292. }
  293. if(!mergedModelMap.containsKey(CONTEXT_PATH_KEY)){
  294. mergedModelMap.put(CONTEXT_PATH_KEY, getContextPath());
  295. }
  296. if(!mergedModelMap.containsKey(CONTEXT_FULL_PATH_KEY)){
  297. mergedModelMap.put(CONTEXT_FULL_PATH_KEY, getContextFullPath());
  298. }
  299. if(!mergedModelMap.containsKey(KEY_OF_ERROR_LIST) && !getErrorList().isEmpty()){
  300. mergedModelMap.put(KEY_OF_ERROR_LIST, getErrorList());
  301. }
  302. //每次请求都生成OTRToken
  303. mergedModelMap.put(Constants.KEY_OF_OTRTOKEN, refreshOTRToken());
  304. //如果有登陆用户,把登陆用户设置到model中
  305. User loginUser = this.getLoginUser();
  306. if(loginUser != null){
  307. mergedModelMap.put(Constants.KEY_OF_LOGIN_USER, loginUser);
  308. }
  309. return mergedModelMap;
  310. }
  311. protected String refreshOTRToken() {
  312. String OTRToken = UUID.randomUUID().toString();
  313. logger.debug("---> generated new OTRToken=" + OTRToken);
  314. Map<String, Object> sessonContext = sessionService.getSessionContext(SessionHelper.getSessionCookieValue(getRequest(), getResponse()));
  315. sessonContext.put(Constants.KEY_OF_OTRTOKEN, OTRToken);
  316. return OTRToken;
  317. }
  318. /**
  319. *
  320. * @return - eg: /to211-web
  321. */
  322. protected String getContextPath() {
  323. return getRequest().getContextPath();
  324. }
  325. /**
  326. *
  327. * @return - eg: http://www.to211.com/to211-web
  328. */
  329. protected String getContextFullPath(){
  330. return getServerFullPath() + getContextPath();
  331. }
  332. /**
  333. *
  334. * @return eg: http://www.to211.com:80
  335. */
  336. private String getServerFullPath() {
  337. StringBuilder contextURL = new StringBuilder();
  338. contextURL.append(getRequest().getScheme())
  339. .append("://")
  340. .append(getRequest().getServerName());
  341. if(getRequest().getServerPort() != DEFAULT_HTTP_PORT){
  342. contextURL.append(":")
  343. .append(getRequest().getServerPort());
  344. }
  345. return contextURL.toString();
  346. }
  347. /**
  348. * 获取全路径http url,eg:http://www.to211.com/url
  349. * @param url - eg:/url
  350. * @return - eg: http://www.to211.com/url
  351. */
  352. protected String getContextFullPathURL(String url){
  353. if(StringUtils.isEmpty(url)){
  354. return url;
  355. }
  356. if(url.startsWith(getServerFullPath())){
  357. return url;
  358. }
  359. return getServerFullPath() + url;
  360. }
  361. /**
  362. * 获取内部转发地址
  363. * @param location - eg: xxx
  364. * @return /forwardInternal?location=xxx
  365. */
  366. protected String getForwardInternalPath(String location){
  367. try {
  368. return String.format("%s/forwardInternal?location=%s", getContextPath(), URLEncoder.encode(location, Constants.DEFAULT_CHARSET));
  369. } catch (UnsupportedEncodingException e) {
  370. logger.error(e);
  371. }
  372. return "";
  373. }
  374. }