001: /*
002: * JFox - The most lightweight Java EE Application Server!
003: * more details please visit http://www.huihoo.org/jfox or http://www.jfox.org.cn.
004: *
005: * JFox is licenced and re-distributable under GNU LGPL.
006: */
007: package org.jfox.mvc.servlet;
008:
009: import java.io.File;
010: import java.io.IOException;
011: import java.io.UnsupportedEncodingException;
012: import java.util.Enumeration;
013: import java.util.HashMap;
014: import java.util.List;
015: import java.util.Map;
016: import javax.servlet.ServletConfig;
017: import javax.servlet.ServletException;
018: import javax.servlet.http.HttpServlet;
019: import javax.servlet.http.HttpServletRequest;
020: import javax.servlet.http.HttpServletResponse;
021:
022: import org.apache.commons.fileupload.FileItem;
023: import org.apache.commons.fileupload.FileUploadException;
024: import org.apache.commons.fileupload.RequestContext;
025: import org.apache.commons.fileupload.disk.DiskFileItemFactory;
026: import org.apache.commons.fileupload.servlet.ServletFileUpload;
027: import org.apache.commons.fileupload.servlet.ServletRequestContext;
028: import org.jfox.mvc.ActionContext;
029: import org.jfox.mvc.FileUploaded;
030: import org.jfox.mvc.WebContextLoader;
031: import org.jfox.mvc.annotation.ActionMethod;
032:
033: /**
034: * 控制器Servlet,所有的Servlet请求,�由该Servlet负责分�
035: * <p/>
036: * ControllerServlet缓å˜æœ‰æ‰€æœ‰Actionï¼Œä¼šæ ¹æ?® URL 规则交给æ£ç¡®çš„ Action 执行, Action则为一个纯粹的Java类,ä¸?ä¾?赖于Web容器
037: * <p/>
038: * ControllerServlet 使用 forward("/WEB-INF/xxx.html") 将请求å?‘é€?到 /WEB-INF ä¸
039: *
040: * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
041: */
042: public class ControllerServlet extends HttpServlet {
043:
044: public static final String PAGE_CONTEXT = "__PAGE_CONTEXT__";
045: public static final String INVOCATION_CONTEXT = "__INVOCATION_CONTEXT__";
046: public static final String MAX_UPLOAD_FILE_SIZE_KEY = "MAX_UPLOAD_FILE_SIZE";
047: public static final String VIEW_DIR_KEY = "VIEW_DIR";
048: public static final String ACTION_SUFFIX_KEY = "ACTION_SUFFIX";
049: public static final String DEFAULT_ENCODING_KEY = "DEFAULT_ENCODING";
050:
051: public static final String MULTIPART = "multipart/";
052:
053: //主è¦?用æ?¥æŽ§åˆ¶request charactor encoding, File Upload, Velocity, Freemarkerçš„ç¼–ç ?
054: public static String DEFAULT_ENCODING = "UTF-8";
055:
056: static String ACTION_SUFFIX = ".do";
057: static String VIEW_DIR = "views";
058: static int MAX_UPLOAD_FILE_SIZE = 5 * 1000 * 1000;
059:
060: public void init(ServletConfig servletConfig)
061: throws ServletException {
062: super .init(servletConfig);
063: String actionSuffix = servletConfig
064: .getInitParameter(ACTION_SUFFIX_KEY);
065: if (actionSuffix != null && actionSuffix.trim().length() != 0) {
066: ACTION_SUFFIX = actionSuffix;
067: }
068: //default encoding
069: String defaultEncoding = servletConfig
070: .getInitParameter(DEFAULT_ENCODING_KEY);
071: if (defaultEncoding != null
072: && defaultEncoding.trim().length() != 0) {
073: DEFAULT_ENCODING = defaultEncoding;
074: }
075:
076: //view dir
077: String viewDir = servletConfig.getInitParameter(VIEW_DIR_KEY);
078: if (viewDir != null && viewDir.trim().length() != 0) {
079: VIEW_DIR = viewDir;
080: }
081:
082: // max upload limit
083: String maxUploadFileSize = servletConfig.getServletContext()
084: .getInitParameter(MAX_UPLOAD_FILE_SIZE_KEY);
085: if (maxUploadFileSize != null
086: && maxUploadFileSize.trim().length() != 0) {
087: MAX_UPLOAD_FILE_SIZE = Integer.parseInt(maxUploadFileSize);
088: }
089:
090: }
091:
092: public static String getActionSuffix() {
093: return ACTION_SUFFIX;
094: }
095:
096: public static String getViewDir() {
097: return VIEW_DIR;
098: }
099:
100: protected void service(HttpServletRequest request,
101: HttpServletResponse response) throws ServletException,
102: IOException {
103: request.setCharacterEncoding(DEFAULT_ENCODING);
104: String pathInfo = request.getPathInfo();
105: if (pathInfo.endsWith(ACTION_SUFFIX)) {
106: // action
107: forwardAction(request, response);
108: } else {
109: // static page or template
110: forwardView(request, response);
111: }
112: }
113:
114: protected void forwardView(HttpServletRequest request,
115: HttpServletResponse response) throws ServletException,
116: IOException {
117: String pathInfo = request.getPathInfo();
118: int slashIndex = pathInfo.indexOf("/", 2);
119: String moduleDirName = pathInfo.substring(1, slashIndex);
120: if (!WebContextLoader.isModuleExists(moduleDirName)) {
121: throw new ServletException("Invalid request url: "
122: + request.getRequestURL());
123: }
124:
125: String filePath = pathInfo.substring(slashIndex);
126: String realPath = WebContextLoader
127: .getModulePathByModuleDirName(moduleDirName)
128: + "/" + VIEW_DIR + filePath;
129: request.getRequestDispatcher(realPath).forward(request,
130: response);
131: }
132:
133: protected void forwardAction(HttpServletRequest request,
134: HttpServletResponse response) throws ServletException,
135: IOException {
136: String pathInfo = request.getPathInfo();
137: String queryString = request.getQueryString();
138: int slashIndex = pathInfo.indexOf("/", 2);
139: String moduleDirName = pathInfo.substring(1, slashIndex);
140: if (!WebContextLoader.isModuleExists(moduleDirName)) {
141: throw new ServletException("Invalid request url: "
142: + request.getRequestURL());
143: }
144:
145: int dotDoIndex = pathInfo.lastIndexOf(ACTION_SUFFIX);
146: int lastSlashIndex = pathInfo.lastIndexOf("/");
147: int actionMethodDotIndex = pathInfo
148: .indexOf(".", lastSlashIndex);
149: String actionName = pathInfo.substring(lastSlashIndex + 1,
150: actionMethodDotIndex);
151: String actionMethodName = pathInfo.substring(
152: actionMethodDotIndex + 1, dotDoIndex);
153:
154: // InvocationContext invocationContext = new InvocationContext(getServletConfig(), request, actionMethodName);
155: // invocationContext.setPostMethod(request.getMethod().toUpperCase().equals("POST"));
156:
157: // 会导致�出的值为数组问题,所以�能使用下�的循环
158: final Map<String, String[]> parameterMap = new HashMap<String, String[]>();
159: final Map<String, FileUploaded> fileUploadedMap = new HashMap<String, FileUploaded>();
160: if (!isMultipartContent(request)) {
161: for (Enumeration enu = request.getParameterNames(); enu
162: .hasMoreElements();) {
163: String key = (String) enu.nextElement();
164: String[] values = request.getParameterValues(key);
165: // invocationContext.addParameter(key, values);
166: if (queryString != null && queryString.contains(key)) { // 是 URL encoding
167: values = decodeQueryStringParameterValues(values);
168: }
169: parameterMap.put(key, values);
170: }
171: } else { // 有文件上ä¼
172: // 从 HTTP servlet 获� fileupload 组件需�的内容
173: RequestContext requestContext = new ServletRequestContext(
174: request);
175: // 判æ–是å?¦åŒ…å?« multipart 内容
176: if (ServletFileUpload.isMultipartContent(requestContext)) {
177: // 创建基于�盘的文件工厂
178: DiskFileItemFactory factory = new DiskFileItemFactory();
179: // 设置直接å˜å‚¨æ–‡ä»¶çš„æž?é™?大å°?,一旦超过则写入临时文件以节约内å˜ã€‚默认为 1024 å—节
180: factory.setSizeThreshold(MAX_UPLOAD_FILE_SIZE);
181: // åˆ›å»ºä¸Šä¼ å¤„ç?†å™¨ï¼Œå?¯ä»¥å¤„ç?†ä»Žå?•ä¸ª HTML ä¸Šä¼ çš„å¤šä¸ªä¸Šä¼ æ–‡ä»¶ã€‚
182: ServletFileUpload upload = new ServletFileUpload(
183: factory);
184: // 最大å…?è®¸ä¸Šä¼ çš„æ–‡ä»¶å¤§å°? 5M
185: upload.setSizeMax(MAX_UPLOAD_FILE_SIZE);
186: upload.setHeaderEncoding(DEFAULT_ENCODING);
187: try {
188: // 处ç?†ä¸Šä¼
189: List items = upload.parseRequest(requestContext);
190: // 由于æ??交了表å?•å—段信æ?¯ï¼Œéœ€è¦?进行循环区分。
191: for (Object item : items) {
192: FileItem fileItem = (FileItem) item;
193: if (fileItem.isFormField()) {
194: // 表�内容
195: // invocationContext.addParameter(fileItem.getFieldName(), new String[]{fileItem.getString(DEFAULT_ENCODING)});
196: parameterMap
197: .put(
198: fileItem.getFieldName(),
199: new String[] { fileItem
200: .getString(DEFAULT_ENCODING) });
201: } else {
202: // 如果�是表�内容,�出 multipart。
203: // ä¸Šä¼ æ–‡ä»¶è·¯å¾„å’Œæ–‡ä»¶ã€?扩展å??。
204: String sourcePath = fileItem.getName();
205: // 获å?–真实文件å??
206: String fileName = new File(sourcePath)
207: .getName();
208: // 读到内å˜æˆ? FileUpload 对象
209: FileUploaded fileUploaded = new FileUploaded(
210: fileItem.getFieldName(), fileName,
211: fileItem.get());
212: // invocationContext.addFileUploaded(fileItem.getFieldName(), fileUploaded);
213: fileUploadedMap.put(
214: fileItem.getFieldName(),
215: fileUploaded);
216: }
217: }
218: } catch (FileUploadException e) {
219: throw new ServletException("File upload failed!", e);
220: }
221: }
222: }
223:
224: try {
225: // �始化 SessionContext,并绑定到线程
226: ActionContext actionContext = new ActionContext(
227: getServletConfig(), request, parameterMap,
228: fileUploadedMap, actionName, actionMethodName);
229: request.setAttribute(INVOCATION_CONTEXT, actionContext);
230: WebContextLoader.invokeAction(moduleDirName, actionName,
231: actionContext);
232: // æ ¹æ?® PageContext.getTargetMethod è¦?决定 forward 还是 redirect
233: if (actionContext.getPageContext().getTargetMethod()
234: .equals(ActionMethod.ForwardMethod.REDIRECT)) {
235: response.sendRedirect(actionContext.getPageContext()
236: .getTargeView());
237: // request.getRequestDispatcher(invocationContext.getPageContext().getTargeView()).(request, response);
238: } else {
239: request.getRequestDispatcher(
240: actionContext.getPageContext().getTargeView())
241: .forward(request, response);
242: }
243: } catch (ServletException e) {
244: throw e;
245: } catch (Exception e) {
246: throw new ServletException(e);
247: }
248: }
249:
250: public static boolean isMultipartContent(HttpServletRequest req) {
251: if (!"POST".equals(req.getMethod().toUpperCase())) {
252: return false;
253: }
254: String contentType = req.getContentType();
255: return contentType != null
256: && contentType.toLowerCase().startsWith(MULTIPART);
257: }
258:
259: public String[] decodeQueryStringParameterValues(String[] values) {
260: if (values != null && values.length > 0) {
261: String[] decodedValues = new String[values.length];
262: for (int i = 0; i < values.length; i++) {
263: try {
264: decodedValues[i] = new String(values[i]
265: .getBytes("ISO-8859-1"), "UTF-8");
266: } catch (UnsupportedEncodingException e) {
267: e.printStackTrace();
268: decodedValues[i] = values[i];
269: }
270: }
271: return decodedValues;
272: } else {
273: return new String[0];
274: }
275: }
276: }
|