package li.mvc;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import li.dao.Page;
import li.model.Action;
import li.model.Field;
import li.util.Convert;
import li.util.Files;
import li.util.Log;
import li.util.Reflect;
import li.util.Verify;
/**
* 负责分发HTTP请求
*
* @author li (limingwei@mail.com)
* @version 0.1.3 (2012-05-08)
*/
public class ActionServlet extends HttpServlet {
private static final long serialVersionUID = -8214041532098707839L;
private static final Log log = Log.init();
private static final String DEV_MODE = Files.config().getProperty("devMode", "false");// 是否开发模式,开发模式才会将异常信息展示到页面
private static final String ENCODING = Files.config().getProperty("servlet.encoding", "UTF-8");// Servlet编码,可在配置文件中配置
private static final String USE_I18N = Files.config().getProperty("servlet.i18n", "false");// 是否使用国际化
public void init(ServletConfig config) throws ServletException {
ServletContext servletContext = config.getServletContext();
servletContext.setAttribute("root", servletContext.getContextPath() + "/");// 默认的环境变量
if ("true".equals(USE_I18N.trim().toLowerCase())) {
servletContext.setAttribute("lang", Files.load(Locale.getDefault().toString()));// 根据Locale.getDefault()初始化国际化,存到servletContext
log.info("Setting default language as ?", Locale.getDefault());
}
}
/**
* 处理请求
*/
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try { // 请求路径路由
Action action = ActionContext.getInstance().getAction(((HttpServletRequest) request).getServletPath(), ((HttpServletRequest) request).getMethod());
if (null != action) {
this.pre(request, response);// 设置字符编码并处理国际化
Context.init(request, response, action);// 初始化Context
log.info("ACTION FOUND: path=\"?\",method=\"?\" action=?()", Context.getRequest().getServletPath(), Context.getRequest().getMethod(), action.actionMethod);
Object result = Reflect.invoke(action.actionInstance, action.actionMethod, this.args());// 执行Action方法
if (result instanceof String && !result.equals("~!@#DONE")) {// 返回值为String且未调用视图方法
Context.view((String) result);// 则Context.view返回视图
}
} else {
response.sendError(404, request.getServletPath() + " not found");
}
log.info("ACTION NOT FOUND: path=\"?\",method=\"?\"", ((HttpServletRequest) request).getServletPath(), ((HttpServletRequest) request).getMethod());
} catch (Throwable e) {
if ("true".equalsIgnoreCase(DEV_MODE)) {
throw new RuntimeException(e + " ", e);
} else {
response.setStatus(500);
log.error(e.getMessage());
e.printStackTrace();
}
}
}
/**
* 设置字符编码并处理国际化
*/
private void pre(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
request.setCharacterEncoding(ENCODING);// 设置编码
response.setCharacterEncoding(ENCODING);
if ("true".equalsIgnoreCase(USE_I18N)) {
String lang = request.getParameter("lang");// 根据Parameter参数设置国际化,存到session
if (!Verify.isEmpty(lang)) {
request.getSession().setAttribute("lang", Files.load(lang));
log.info("Setting language for ?", lang);
}
}
}
/**
* 适配参数
*/
private Object[] args() {
Action action = Context.getAction();
Object[] args = new Object[action.argTypes.length]; // Action方法参数值列表
for (int i = 0; i < action.argTypes.length; i++) {// Action方法参数适配
String key = (null == action.argAnnotations[i]) ? action.argNames[i] : action.argAnnotations[i].value();// ParameterKey
if (Verify.basicType(action.argTypes[i]) && !action.argTypes[i].isArray()) { // 单个基本类型
args[i] = Convert.toType(action.argTypes[i], Context.getRequest().getParameter(key));
} else if (Verify.basicType(action.argTypes[i]) && action.argTypes[i].isArray()) { // 基本类型的数组
args[i] = Context.getArray(action.argTypes[i].getComponentType(), key);
} else if (ServletRequest.class.isAssignableFrom(action.argTypes[i])) { // Request
args[i] = Context.getRequest();
} else if (ServletResponse.class.isAssignableFrom(action.argTypes[i])) { // Response
args[i] = Context.getResponse();
} else if (Page.class.isAssignableFrom(action.argTypes[i])) { // Page
args[i] = Context.getPage(key);
} else if (Field.list(action.argTypes[i], false).size() > 0 || Map.class.isAssignableFrom(action.argTypes[i])) {
key = (null == action.argAnnotations[i]) ? action.argNames[i] + "." : action.argAnnotations[i].value();
args[i] = Context.get(action.argTypes[i], key);// 数据对象,POJO,如果没加@Arg注解,则key为参数名+"."
}
}
return args;
}
}