BaseController.java 8.92 KB
/**
 * Copyright © 2015-2018 ODM All rights reserved.
 */
package com.thinkgem.jeesite.common.web;

import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import javax.validation.Validator;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.xml.sax.SAXException;

import com.google.common.collect.Maps;
import com.thinkgem.jeesite.common.beanvalidator.BeanValidators;
import com.thinkgem.jeesite.common.mapper.JsonMapper;
import com.thinkgem.jeesite.common.utils.DateUtils;

/**
 * 控制器支持类
 * 
 * @author ThinkGem
 * @version 2013-3-23
 */
public abstract class BaseController {

	/**
	 * 日志对象
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 管理基础路径
	 */
	@Value("${adminPath}")
	protected String adminPath;

	/**
	 * 前端基础路径
	 */
	@Value("${frontPath}")
	protected String frontPath;

	/**
	 * 前端URL后缀
	 */
	@Value("${urlSuffix}")
	protected String urlSuffix;

	/**
	 * 验证Bean实例对象
	 */
	@Autowired
	protected Validator validator;

	/**
	 * 服务端参数有效性验证
	 * 
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功:返回true;验证失败:将错误信息添加到 message 中
	 */
	protected boolean beanValidator(Model model, Object object, Class<?>... groups) {
		try {
			BeanValidators.validateWithException(validator, object, groups);
		} catch (ConstraintViolationException ex) {
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败:");
			addMessage(model, list.toArray(new String[] {}));
			return false;
		}
		return true;
	}

	/**
	 * 服务端参数有效性验证
	 * 
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功:返回true;严重失败:将错误信息添加到 flash message 中
	 */
	protected boolean beanValidator(RedirectAttributes redirectAttributes, Object object, Class<?>... groups) {
		try {
			BeanValidators.validateWithException(validator, object, groups);
		} catch (ConstraintViolationException ex) {
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败:");
			addMessage(redirectAttributes, list.toArray(new String[] {}));
			return false;
		}
		return true;
	}

	/**
	 * 服务端参数有效性验证
	 * 
	 * @param object 验证的实体对象
	 * @param groups 验证组,不传入此参数时,同@Valid注解验证
	 * @return 验证成功:继续执行;验证失败:抛出异常跳转400页面。
	 */
	protected void beanValidator(Object object, Class<?>... groups) {
		BeanValidators.validateWithException(validator, object, groups);
	}

	/**
	 * 添加Model消息
	 * 
	 * @param message
	 */
	protected void addMessage(Model model, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages) {
			sb.append(message).append(messages.length > 1 ? "<br/>" : "");
		}
		model.addAttribute("message", sb.toString());
	}

	/**
	 * 添加Flash消息
	 * 
	 * @param message
	 */
	protected void addMessage(RedirectAttributes redirectAttributes, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages) {
			sb.append(message).append(messages.length > 1 ? "<br/>" : "");
		}
		redirectAttributes.addFlashAttribute("message", sb.toString());
	}

	/**
	 * 客户端返回JSON字符串
	 * 
	 * @param response
	 * @param object
	 * @return
	 */
	protected String renderString(HttpServletResponse response, Object object) {
		logger.info("json :{}", JsonMapper.toJsonString(object));
		return renderString(response, JsonMapper.toJsonString(object), "application/json");
	}

	/**
	 * 客户端返回xml字符串
	 * 
	 * @param response
	 * @param object
	 * @return
	 * @throws SAXException 
	 * @throws IOException 
	 */
	protected String renderString(HttpServletResponse response, Map  head,Map  data) throws IOException, SAXException {
		Map<String, Map<String, Object>> root_map = Maps.newHashMap();
		Map<String, Object> root= Maps.newHashMap();
		root.put("Head", head);
		root.put("RecordSet", data);
		root_map.put("Root", root);
		
		logger.info("json :{}", JsonMapper.toJsonString(root_map));
		String xml = jsonToPrettyXml(root_map);

		logger.info("xml :{}", xml);
		return renderString(response, xml, "application/xml");
	}

	private final String ENCODING = "UTF-8";

	public String jsonToPrettyXml(Map<String, Map<String, Object>> map) throws IOException, SAXException {
		Document document = jsonToDocument(map);

		/* 格式化xml */
		OutputFormat format = OutputFormat.createPrettyPrint();

		// 设置缩进为4个空格
		//format.setIndent(" ");
		//format.setIndentSize(4);

		StringWriter formatXml = new StringWriter();
		//XMLWriter writer = new XMLWriter(formatXml, format);
		XMLWriter writer = new XMLWriter(formatXml);
		writer.write(document);

		return formatXml.toString();
	}

	/**
	 * JSON对象转Document对象
	 * 
	 * @param json JSON对象
	 * @return Document对象
	 * @throws SAXException
	 */
	public Document jsonToDocument(Map<String, Map<String, Object>> map) throws SAXException {
		Document document = DocumentHelper.createDocument();
		document.setXMLEncoding(ENCODING);

		// root对象只能有一个
		for (String rootKey : map.keySet()) {
			Element root = addElement(map.get(rootKey), rootKey);
			document.add(root);
			break;
		}
		return document;
	}

	/**
	 * JSON对象转Element对象
	 * 
	 * @param json     JSON对象
	 * @param nodeName 节点名称
	 * @return Element对象
	 */
	public Element addElement(Map<String, Object> map, String nodeName) {
		Element node = DocumentHelper.createElement(nodeName);
		for (String key : map.keySet()) { 
			Object child = map.get(key);
			if (child instanceof Map) {
				node.add(addElement((Map<String, Object>) child, key));
			}else if (child instanceof List) {
				addElement((List<Map>) child, key, node);
			}else{
				Element element = DocumentHelper.createElement(key);
				element.setText(child == null ? "" : child.toString());
				node.add(element);
			}
		}
		return node;
	}

	public void addElement(List<Map> list, String nodeName, Element parentnode) {
		for (Map map : list) {
			parentnode.add(addElement(map, nodeName));
		}

	}

	/**
	 * 客户端返回字符串
	 * 
	 * @param response
	 * @param string
	 * @return
	 */
	protected String renderString(HttpServletResponse response, String string, String type) {
		try {
			response.reset();
			response.setContentType(type);
			response.setCharacterEncoding("utf-8");
			response.getWriter().print(string);
			return null;
		} catch (IOException e) {
			return null;
		}
	}

	/**
	 * 参数绑定异常
	 */
	@ExceptionHandler({ BindException.class, ConstraintViolationException.class, ValidationException.class })
	public String bindException() {
		return "error/400";
	}

	/**
	 * 授权登录异常
	 */
	@ExceptionHandler({ AuthenticationException.class })
	public String authenticationException() {
		return "error/403";
	}

	/**
	 * 初始化数据绑定 1. 将所有传递进来的String进行HTML编码,防止XSS攻击 2. 将字段中Date类型转换为String类型
	 */
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		// String类型转换,将所有传递进来的String进行HTML编码,防止XSS攻击
		binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(text == null ? null : StringEscapeUtils.escapeHtml4(text.trim()));
			}

			@Override
			public String getAsText() {
				Object value = getValue();
				return value != null ? value.toString() : "";
			}
		});
		// Date 类型转换
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(DateUtils.parseDate(text));
			}
//			@Override
//			public String getAsText() {
//				Object value = getValue();
//				return value != null ? DateUtils.formatDateTime((Date)value) : "";
//			}
		});
	}

}