package org.nutz.mvc;
import java.io.IOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.nutz.Nutz;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.IocContext;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.nutz.lang.Strings;
import org.nutz.lang.util.Context;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.config.AtMap;
import org.nutz.mvc.impl.NutMessageMap;
import org.nutz.mvc.ioc.SessionIocContext;
/**
* Mvc 相关帮助函数
*
* @author zozoh(zozohtnt@gmail.com)
* @author wendal(wendal1985@gmail.com)
*/
public abstract class Mvcs {
// TODO 这个变量应该在 1.b.46 之后的某一个版本删掉
public static final String DEFAULT_MSGS = "$default";
public static final String MSG = "msg";
public static final String LOCALE_KEY = "nutz_mvc_localization_key";
// PS: 如果这个修改导致异常,请报issue,并将这个变量设置为true
public static boolean disableFastClassInvoker = false;
// 实现显示行号, 如果禁用, 轻微加速启动
public static boolean DISPLAY_METHOD_LINENUMBER = true;
// 如果一个Resp已经commit过了,那么是否跳过渲染呢
public static boolean SKIP_COMMITTED = false;
public static boolean DISABLE_X_POWERED_BY = false;
public static String X_POWERED_BY = "nutz/"+Nutz.version()+" <nutzam.com>";
// ====================================================================
public static Map<String, Object> getLocaleMessage(String key) {
Map<String, Map<String, Object>> msgss = getMessageSet();
if (null != msgss)
return msgss.get(key);
return null;
}
/**
* 获取当前请求对象的字符串表
*
* @param req
* 请求对象
* @return 字符串表
*/
@SuppressWarnings("unchecked")
public static Map<String, String> getMessages(ServletRequest req) {
return (Map<String, String>) req.getAttribute(MSG);
}
/**
* 获取当前请求对象的字符串表(NutMessageMap 封装)
*
* @param req
* 请求对象
* @return 字符串表
*/
public static NutMessageMap getMessageMap(ServletRequest req) {
return (NutMessageMap) req.getAttribute(MSG);
}
/**
* 获取当前请求对象的字符串表中的某一个字符串
*
* @param req
* 请求对象
* @param key
* 字符串键值
* @return 字符串内容
*/
public static String getMessage(ServletRequest req, String key) {
Map<String, String> map = getMessages(req);
if (null != map)
return map.get(key);
return null;
}
/**
* 获取当前会话的本地字符串集合的键值;如果当前 HTTP 会话不存在,则返回 null
*
* @return 当前会话的本地字符串集合的键值;如果当前 HTTP 会话不存在,则返回 null
*/
public static String getLocalizationKey() {
return (String) getSessionAttrSafe(LOCALE_KEY);
}
/**
* 设置本地化字符串的键值
* <p>
* 如果你用的是 Nutz.Mvc 默认的本地化机制,那么你的本地字符串键值,相当于一个你目录名。 <br>
* 比如 "zh_CN" 等
*
* @param key
* 键值
* @return 是否设置成功
*/
public static boolean setLocalizationKey(String key) {
HttpSession sess = getHttpSession();
if (null == sess)
return false;
sess.setAttribute(LOCALE_KEY, key);
return true;
}
/**
* 返回当前加载了的本地化字符串的键值
*
* @return 当前都加载了哪些种字符串的 KEY
*/
public static Set<String> getLocalizationKeySet() {
Map<String, Map<String, Object>> msgss = getMessageSet();
if (null == msgss)
return new HashSet<String>();
return msgss.keySet();
}
/**
* 默认的本地化字符串 KEY,当为 NULL 时,Nutz.Mvc 会随便用一个
*/
private static String default_localization_key = null;
/**
* 设置默认的多国语言
*
* @param key
* 默认的多国语言 KEY
*/
public static void setDefaultLocalizationKey(String key) {
default_localization_key = key;
}
/**
* 返回默认的本地化字符串 KEY
*
* @return 默认的本地化字符串 KEY
*/
public static String getDefaultLocalizationKey() {
return default_localization_key;
}
/**
* 为当前的 HTTP 请求对象设置一些必要的属性。包括:
* <ul>
* <li>本地化子字符串 => ${msg}
* <li>应用的路径名 => ${base}
* </ul>
*
* @param req
* HTTP 请求对象
*/
public static void updateRequestAttributes(HttpServletRequest req) {
// 初始化本次请求的多国语言字符串
Map<String, Map<String, Object>> msgss = getMessageSet();
if (msgss == null && !ctx().localizations.isEmpty())
msgss = ctx().localizations.values().iterator().next();
if (null != msgss) {
Map<String, Object> msgs = null;
String lKey = Strings.sBlank(Mvcs.getLocalizationKey(), getDefaultLocalizationKey());
if (!Strings.isBlank(lKey))
msgs = msgss.get(lKey);
// 没有设定特殊的 Local 名字,随便取一个
if (null == msgs) {
if (msgss.size() > 0)
msgs = msgss.values().iterator().next();
}
// 记录到请求中
req.setAttribute(MSG, msgs);
}
// 记录一些数据到请求对象中
req.setAttribute("base", req.getContextPath());
req.setAttribute("$request", req);
}
/**
* 获取当前请求的路径,并去掉后缀
*
* @param req
* HTTP 请求对象
*/
public static String getRequestPath(HttpServletRequest req) {
return getRequestPathObject(req).getPath();
}
/**
* 获取当前请求的路径,并去掉后缀
*
* @param req
* HTTP 请求对象
*/
public static RequestPath getRequestPathObject(HttpServletRequest req) {
String url = req.getPathInfo();
if (null == url)
url = req.getServletPath();
return getRequestPathObject(url);
}
/**
* 获取当前请求的路径,并去掉后缀
*
* @param url
* 请求路径的URL
*/
public static RequestPath getRequestPathObject(String url) {
RequestPath rr = new RequestPath();
rr.setUrl(url);
if (null != url) {
int lio = 0;
if (!url.endsWith("/")) {
int ll = url.lastIndexOf('/');
lio = url.lastIndexOf('.');
if (lio < ll)
lio = -1;
}
if (lio > 0) {
rr.setPath(url.substring(0, lio));
rr.setSuffix(url.substring(lio + 1));
} else {
rr.setPath(url);
rr.setSuffix("");
}
} else {
rr.setPath("");
rr.setSuffix("");
}
return rr;
}
/**
* 注销当前 HTTP 会话。所有 Ioc 容器存入的对象都会被注销
*
* @param session
* HTTP 会话对象
*/
public static void deposeSession(HttpSession session) {
if (session != null)
new SessionIocContext(session).depose();
}
/**
* 它将对象序列化成 JSON 字符串,并写入 HTTP 响应
*
* @param resp
* 响应对象
* @param obj
* 数据对象
* @param format
* JSON 的格式化方式
* @throws IOException
* 写入失败
*/
public static void write(HttpServletResponse resp, Object obj, JsonFormat format)
throws IOException {
write(resp, resp.getWriter(), obj, format);
}
public static void write(HttpServletResponse resp, Writer writer, Object obj, JsonFormat format)
throws IOException {
resp.setHeader("Cache-Control", "no-cache");
if (resp.getContentType() == null)
resp.setContentType("text/plain");
// by mawm 改为直接采用resp.getWriter()的方式直接输出!
Json.toJson(writer, obj, format);
resp.flushBuffer();
}
// ==================================================================
private static final ThreadLocal<String> NAME = new ThreadLocal<String>();
/**
* NutMvc的上下文
*/
@Deprecated
public static NutMvcContext ctx;
public static NutMvcContext ctx() {
ServletContext sc = getServletContext();
if (sc == null) {
if (ctx == null)
ctx = new NutMvcContext();
return ctx;
}
NutMvcContext c = (NutMvcContext) getServletContext().getAttribute("__nutz__mvc__ctx");
if (c == null) {
c = new NutMvcContext();
getServletContext().setAttribute("__nutz__mvc__ctx", c);
ctx = c;
}
return c;
}
private static ServletContext def_servletContext;
private static ThreadLocal<ServletContext> servletContext = new ThreadLocal<ServletContext>();
/**
* 获取 HTTP 请求对象
*
* @return HTTP 请求对象
*/
public static final HttpServletRequest getReq() {
return reqt().getAs(HttpServletRequest.class, "req");
}
/**
* 获取 HTTP 响应对象
*
* @return HTTP 响应对象
*/
public static final HttpServletResponse getResp() {
return reqt().getAs(HttpServletResponse.class, "resp");
}
public static final String getName() {
return NAME.get();
}
/**
* 获取 Action 执行的上下文
*
* @return Action 执行的上下文
*/
public static final ActionContext getActionContext() {
return reqt().getAs(ActionContext.class, "ActionContext");
}
public static void set(String name, HttpServletRequest req, HttpServletResponse resp) {
NAME.set(name);
reqt().set("req", req);
reqt().set("resp", resp);
}
/**
* 设置 Servlet 执行的上下文
*
* @param servletContext
* Servlet 执行的上下文
*/
public static void setServletContext(ServletContext servletContext) {
if (servletContext == null) {
Mvcs.servletContext.remove();
}
if (def_servletContext == null)
def_servletContext = servletContext;
Mvcs.servletContext.set(servletContext);
}
/**
* 设置 Action 执行的上下文
*
* @param actionContext
* Action 执行的上下文
*/
public static void setActionContext(ActionContext actionContext) {
reqt().set("ActionContext", actionContext);
}
/**
* 获取 Servlet 执行的上下文
*
* @return Servlet 执行的上下文
*/
public static ServletContext getServletContext() {
ServletContext cnt = servletContext.get();
if (cnt != null)
return cnt;
return def_servletContext;
}
/**
* 设置对象装配的上下文环境
*
* @param iocContext
* 对象装配的上下文环境
*/
public static void setIocContext(IocContext iocContext) {
reqt().set("IocContext", iocContext);
}
/**
* 获取对象装配的上下文环境
*
* @return 进行对象装配的上下文环境
*/
public static IocContext getIocContext() {
return reqt().getAs(IocContext.class, "IocContext");
}
// 新的,基于ThreadLoacl改造过的Mvc辅助方法
// ====================================================================
/**
* 获取全局的Ioc对象
*
* @return 全局的Ioc对象
*/
public static Ioc getIoc() {
return ctx().iocs.get(getName());
}
public static void setIoc(Ioc ioc) {
ctx().iocs.put(getName(), ioc);
}
public static AtMap getAtMap() {
return ctx().atMaps.get(getName());
}
public static void setAtMap(AtMap atmap) {
ctx().atMaps.put(getName(), atmap);
}
public static Map<String, Map<String, Object>> getMessageSet() {
return ctx().localizations.get(getName());
}
public static void setMessageSet(Map<String, Map<String, Object>> messageSet) {
ctx().localizations.put(getName(), messageSet);
}
public static void setNutConfig(NutConfig config) {
ctx().nutConfigs.put(getName(), config);
}
public static NutConfig getNutConfig() {
return ctx().nutConfigs.get(getName());
}
// ==================================================================
/**
* 重置当前线程所持有的对象
*/
public static Context resetALL() {
Context context = reqt();
NAME.set(null);
ctx().removeReqCtx();
return context;
}
public static HttpSession getHttpSession() {
return getHttpSession(true);
}
public static HttpSession getHttpSession(boolean createNew) {
HttpServletRequest req = getReq();
if (null == req)
return null;
return req.getSession(createNew);
}
public static void close() {
ctx().clear();
ctx().close();
ctx = new NutMvcContext();
}
public static Context reqt() {
return ctx().reqCtx();
}
public static Object getSessionAttrSafe(String key) {
try {
HttpSession session = getHttpSession(false);
return session != null ? session.getAttribute(key) : null;
}
catch (Exception e) {
return false;
}
}
public static void setSessionAttrSafe(String key, Object val, boolean sessionCreate) {
try {
HttpSession session = getHttpSession(sessionCreate);
if (session != null)
session.setAttribute(key, val);
}
catch (Exception e) {
}
}
public static NutMap toParamMap(Reader r, String enc) throws IOException {
try {
NutMap map = new NutMap();
char[] buf = new char[1];
StringBuilder sb = new StringBuilder();
while (true) {
int len = r.read(buf);
if (len == 0)
continue;
if (buf[0] == '&' || len < 0) {
String[] tmp = sb.toString().split("=");
if (tmp != null && tmp.length == 2) {
map.put(URLDecoder.decode(tmp[0], enc), URLDecoder.decode(tmp[1], enc));
}
if (len < 0)
break;
sb.setLength(0);
} else {
sb.append(buf[0]);
}
}
return map;
}
catch (UnsupportedEncodingException e) {
throw new IOException(e);
}
}
}