精华帖 (4) :: 良好帖 (13) :: 新手帖 (0) :: 隐藏帖 (13)
|
|
---|---|
作者 | 正文 |
发表时间:2010-06-02
VelocityActionServlet是整个MVC框架的核心类,拦截所有的Action请求,分发给不同的Action进行处理。 init()方法初始化了系统需要的资源和VelocityEngine。 doProcess()是这个类的核心方法,处理用户请求,获取context数据,获取模板,合成html package com.zzq.velocity.core; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.collections.ExtendedProperties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.context.Context; import org.apache.velocity.io.VelocityWriter; public class VelocityActionServlet extends HttpServlet { private static Log log = LogFactory.getLog(VelocityActionServlet.class); /** * request放入VelocityContext中的key */ public static final String REQUEST = "request"; /** * response放入VelocityContext中的key */ public static final String RESPONSE = "response"; public static final String CONTENT_TYPE = "default.contentType"; public static final String OUTPUT_ENCODING = "output.encoding"; /** * 默认的输出编码 */ public static final String DEFAULT_OUTPUT_ENCODING = "UTF-8"; /** * velocity.properties在web.xml文件默认的key */ protected static final String INIT_PROPS_KEY = "org.apache.velocity.properties"; /** * velocity.properties在默认的路径 */ protected static final String DEFAULT_PROPERTIES_PATH = "/WEB-INF/velocity.properties"; /** * 默认的ContextType */ public static final String DEFAULT_CONTENT_TYPE = "text/html"; /** * 对输出流维护的池 */ private ObjectPool<VelocityWriter> pool = new ObjectPool<VelocityWriter>(40); private VelocityEngine velocity = null; /** * 例如user.do?method=add -> 会调用UserAction的add方法 相当于DispatchAction功能 */ private static final String DEFAULT_PARAMETER_METHOD = "method"; private static final String INIT_PARAMETER_KEY = "parameter"; private String parameterMethod; /** * 最终默认的ContentType */ private String defaultContentType; private static final String INIT_TEMPLATEPATH_KEY = "templatePath"; private static final String FILE_RESOURCE_LOADER_PATH = "file.resource.loader.path"; public void init(ServletConfig config) throws ServletException { super.init(config); /** * 初始化Velocity引擎 */ initVelocity(config); defaultContentType = (String)getVelocityProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); String encoding = (String)getVelocityProperty(OUTPUT_ENCODING, DEFAULT_OUTPUT_ENCODING); parameterMethod = findInitParameter(config, INIT_PARAMETER_KEY, DEFAULT_PARAMETER_METHOD); int index = defaultContentType.lastIndexOf(";"); if(index < 0) { defaultContentType += "; charset=" + encoding; } } /** * 初始化Velocity引擎 * @param config * @throws ServletException */ protected void initVelocity(ServletConfig config) throws ServletException { try { velocity = new VelocityEngine(); ExtendedProperties p = loadConfiguration(config); String templatePath = findInitParameter(config, INIT_TEMPLATEPATH_KEY); templatePath = config.getServletContext().getRealPath("/") + templatePath; velocity.setProperty(FILE_RESOURCE_LOADER_PATH, templatePath); velocity.setExtendedProperties(p); velocity.init(); } catch (Exception e) { log.error("初始化velocity引擎时出错!"); throw new ServletException(e); } } protected String getVelocityProperty(String key, String defaultValue) { String value = (String)velocity.getProperty(key); if(null == value || "".equals(value.trim())) { value = defaultValue; } return value; } /** * 加载velocity.properties配置文件 */ protected ExtendedProperties loadConfiguration(ServletConfig config) { String propsFile = findInitParameter(config, INIT_PROPS_KEY); if(null == propsFile) { propsFile = DEFAULT_PROPERTIES_PATH; } ExtendedProperties properties = new ExtendedProperties(); InputStream inputStream = getServletContext().getResourceAsStream(propsFile); try { inputStream = getServletContext().getResourceAsStream(propsFile); if(null != inputStream) { properties.load(inputStream); } } catch (IOException e) { throw new RuntimeException(e); } finally { if(null != inputStream) { try { inputStream.close(); } catch (IOException e) { throw new RuntimeException("关闭" + propsFile + "文件时出现异常!"); } } } return properties; } protected String findInitParameter(ServletConfig config, String key) { String value = config.getInitParameter(key); if(null == value || "".equals(value.trim())) { value = config.getServletContext().getInitParameter(key); } return value; } protected String findInitParameter(ServletConfig config, String key, String defaultValue) { String value = config.getInitParameter(key); if(null == value || "".equals(value.trim())) { value = config.getServletContext().getInitParameter(key); } if(null == value || "".equals(value.trim())) { value = defaultValue; } return value; } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doProcess(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doProcess(request, response); } /** * 请求处理的核心方法 * @param request * @param response */ protected void doProcess(HttpServletRequest request, HttpServletResponse response) { Context context = null; try { initServletActionContext(request, response); initActionContext(request); setContentType(request, response); Action action = getAction(request); String templateName = doExecute(action, request, response); //在Action中调用response.sendRedirect(); if(null == templateName) { return ; } context = createContext(action, request, response); Template template = handleRequest(templateName, request, response, context); mergeTemplate(template, context, response); } catch(Exception e) { try { e.printStackTrace(response.getWriter()); response.getWriter().flush(); } catch (IOException e1) { throw new RuntimeException(e); } } finally { destoryServletActionContext(); destoryActionContext(request); } } /** * 给ServletActionContext赋值 * @param request * @param response */ protected void initServletActionContext(HttpServletRequest request, HttpServletResponse response) { ServletActionContext.setRequest(request); ServletActionContext.setResponse(response); } /** * 给ActionContext赋值 * @param request */ protected void initActionContext(HttpServletRequest request) { //处理request Map<String, Object> values = new HashMap<String, Object>(); Enumeration enumeration = request.getAttributeNames(); while(enumeration.hasMoreElements()) { String key = (String)enumeration.nextElement(); values.put(key, request.getAttribute(key)); } ActionContext.setRequest(values); //处理session values = new HashMap<String, Object>(); HttpSession session = request.getSession(); if(null != session) { session = request.getSession(true); } enumeration = session.getAttributeNames(); while(enumeration.hasMoreElements()) { String key = (String)enumeration.nextElement(); values.put(key, session.getAttribute(key)); } ActionContext.setSession(values); //处理ServletContext values = new HashMap<String, Object>(); ServletContext servletContext = session.getServletContext(); enumeration = servletContext.getAttributeNames(); while(enumeration.hasMoreElements()) { String key = (String)enumeration.nextElement(); values.put(key, session.getAttribute(key)); } ActionContext.setServletContext(values); } /** * 销毁当前线程的ServletActionContext */ protected void destoryServletActionContext() { ServletActionContext.destory(); } /** * 销毁当前线程的ActionContext * @param request */ protected void destoryActionContext(HttpServletRequest request) { Map<String, Object> values = ActionContext.getContext().getRequest(); for(Iterator<String> iter = values.keySet().iterator(); iter.hasNext(); ) { String key = iter.next(); request.setAttribute(key, values.get(key)); } values = ActionContext.getContext().getSession(); HttpSession session = request.getSession(); for(Iterator<String> iter = values.keySet().iterator(); iter.hasNext(); ) { String key = iter.next(); session.setAttribute(key, values.get(key)); } values = ActionContext.getContext().getServletContext(); ServletContext servletContext = session.getServletContext(); for(Iterator<String> iter = values.keySet().iterator(); iter.hasNext(); ) { String key = iter.next(); servletContext.setAttribute(key, values.get(key)); } ActionContext.destory(); } protected String doExecute(Action action, HttpServletRequest request, HttpServletResponse response) throws Exception { String methodName = request.getParameter(parameterMethod); if(null == methodName || "".equals(methodName.trim())) { methodName = "execute"; } Method method = action.getClass().getMethod(methodName); String templateName = (String)method.invoke(action); return templateName; } protected Context createContext(Action action, HttpServletRequest request, HttpServletResponse response){ VelocityContext context = new VelocityContext(); context.put(REQUEST, request); context.put(RESPONSE, response); Map<String, Object> params = action.getContext(); for(Iterator<String> iter = params.keySet().iterator(); iter.hasNext(); ) { String key = iter.next(); Object value = params.get(key); context.put(key, value); } return context; } private Action getAction(HttpServletRequest request) { String requestURI = request.getRequestURI(); String actionName = requestURI.substring(requestURI.indexOf('/', 1), requestURI.lastIndexOf('.')); Action action = (Action)BeanFactory.getBean(actionName); if(null == action) { throw new RuntimeException("没有找到路径为:" + actionName + "对应的Action"); } return action; } protected void setContentType(HttpServletRequest request, HttpServletResponse response) { response.setContentType(defaultContentType); } protected Template handleRequest(String templateName, HttpServletRequest request, HttpServletResponse response, Context ctx) { //do something...... Template template = null; try { template = velocity.getTemplate(templateName); } catch (Exception e) { throw new RuntimeException(e); } return template; } protected void mergeTemplate(Template template, Context context,HttpServletResponse response) throws UnsupportedEncodingException, IOException { VelocityWriter vw = null; Writer writer = getResponseWriter(response); try { vw = pool.get(); if(null == vw) { vw = new VelocityWriter(writer, 4*1024, true); } else { vw.recycle(writer); } template.merge(context, writer); } finally { if(null != vw) { vw.flush(); vw.recycle(null); pool.put(vw); } } } protected Writer getResponseWriter(HttpServletResponse response) throws UnsupportedEncodingException, IOException { Writer writer = null; try { writer = response.getWriter(); } catch (IllegalStateException e) { String encoding = response.getCharacterEncoding(); if (encoding == null) { encoding = DEFAULT_OUTPUT_ENCODING; } writer = new OutputStreamWriter(response.getOutputStream(), encoding); } return writer; } } 这是一个简单的Bean工程实现,加载类路径下的beans.properties文件(这里完全可以用xml,这都是次要的问题,不是核心问题,等以后有时间了可以继续改进) beans.properties文件, 路径=Action类,如: /user=com.velocity.test.action.UserAction package com.zzq.velocity.core; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; public class BeanFactory { private static Map<String, String> map = new HashMap<String, String>(); static { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("beans.properties"); try { Properties prop = new Properties(); prop.load(is); Iterator iter = prop.keySet().iterator(); while(iter.hasNext()) { String key = (String)iter.next(); String className = prop.getProperty(key); map.put(key, className); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("初始化BeanFactory失败", e); } finally { try { if(null != is) { is.close(); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } } public static Object getBean(String id) { //prototype String className = map.get(id); if(null == className) { return null; } Object action = null; try { action = Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("创建Action类:" + className + "失败", e); } return action; } } ObjectPool对象池的实现,主要是对Writer进行管理。 package com.zzq.velocity.core; import java.util.ArrayList; import java.util.List; /** * 对象池 * @author zzq * */ public class ObjectPool<T> { /** * 默认池大小 */ public static final int DEFAULT_POOL_SIZE = 10; private int max; private int current=-1; private List<T> pool = null; public ObjectPool() { this(DEFAULT_POOL_SIZE); } public ObjectPool(int size) { max = size; pool = new ArrayList<T>(size); } public T get() { T obj = null; synchronized (this) { if(current > -1) { obj = pool.get(current); current --; } } return obj; } public void put(T obj) { synchronized (this) { current ++; if(current < max) { pool.add(obj); return ; } current --; } } public int getMax() { return max; } public List<T> getPool() { return pool; } } VelocityWriter类对Writer进行修饰,加入了Buffer。 package com.zzq.velocity.core; import java.io.IOException; import java.io.Writer; public class VelocityWriter extends Writer { private int bufferSize; private boolean autoFlush; private Writer writer; private char cb[]; private int next; private static final int DEFAULT_CHARBUFFER_SIZE = 8 * 1024; public VelocityWriter(Writer writer) { this(writer, DEFAULT_CHARBUFFER_SIZE, true); } public VelocityWriter(Writer writer, int size, boolean isFlush) { if(size < 0) { throw new IllegalArgumentException("Buffer size < 0"); } this.bufferSize = size; this.autoFlush = isFlush; this.writer = writer; cb = size > 0 ? new char[size] : null; next = 0; } public int getBufferSize() { return bufferSize; } public boolean isAutoFlush() { return autoFlush; } private final void flushBuffer() throws IOException { if(bufferSize == 0) { return ; } if(next == 0) { return ; } writer.write(cb, 0, next); this.next = 0; } public final void clear() { next = 0; } private final void bufferOverflow() throws IOException { throw new IOException("Buffer over flow!"); } public final void write(int c) throws IOException { if(bufferSize == 0) { writer.write(c); return ; } if(next >= bufferSize) { if(autoFlush) { flushBuffer(); } else { bufferOverflow(); } } cb[next++] = (char)c; } public final void write(char buf[]) throws IOException { write(buf, 0, buf.length); } public final void write(String s, int off, int len) throws IOException { write(s.toCharArray(), off, len); } public final void write(String s) throws IOException { write(s, 0, s.length()); } @Override public void write(char[] cbuf, int off, int len) throws IOException { if(bufferSize == 0) { writer.write(cbuf, off, len); return ; } if (len == 0) { return; } if (len >= bufferSize) { if (autoFlush) flushBuffer(); else bufferOverflow(); writer.write(cbuf, off, len); return; } if(len + off > cbuf.length) { throw new IllegalArgumentException("len + off > cbuf.length"); } while(len > 0) { int b = len > bufferSize - next ? bufferSize - next : len; System.arraycopy(cb, next, cbuf, off, b); next += b; if(next >= bufferSize) { if(autoFlush) { flushBuffer(); } else { bufferOverflow(); } } off += b; len -= b; } } public final void recycle(Writer writer) { this.writer = writer; clear(); } @Override public void close() throws IOException { if(writer != null) { flush(); writer.close(); } } @Override public void flush() throws IOException { flushBuffer(); writer.flush(); } } ServletActionContext这个类,挺简单的,一看就能明白,和Struts2的ServletActionContext功能一样。 package com.zzq.velocity.core; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class ServletActionContext { private static ThreadLocal<HttpServletRequest> reqContext = new ThreadLocal<HttpServletRequest>(); private static ThreadLocal<HttpServletResponse> respContext = new ThreadLocal<HttpServletResponse>(); public static void setRequest(HttpServletRequest request) { reqContext.set(request); } public static void setResponse(HttpServletResponse response) { respContext.set(response); } public static HttpServletRequest getRequset() { return reqContext.get(); } public static HttpServletResponse getResponse() { return respContext.get(); } public static HttpSession getSession() { return reqContext.get().getSession(); } public static ServletContext getServletContext() { return reqContext.get().getSession().getServletContext(); } public static void destory() { reqContext.remove(); respContext.remove(); } } 这个更不用说了,玩过Struts2的人一看就知道。 package com.zzq.velocity.core; import java.util.Map; /** * 将Servlet API 进行解耦 * @author zzq * */ public class ActionContext { private static ActionContext instance = new ActionContext(); private static ThreadLocal<Map<String, Object>> request = new ThreadLocal<Map<String, Object>>(); private static ThreadLocal<Map<String, Object>> session = new ThreadLocal<Map<String, Object>>(); private static ThreadLocal<Map<String, Object>> servletContext = new ThreadLocal<Map<String, Object>>(); private ActionContext() {} public static ActionContext getContext() { return instance; } public static void setRequest(Map<String, Object> value) { request.set(value); } public static void setSession(Map<String, Object> value) { session.set(value); } public static void setServletContext(Map<String, Object> value) { servletContext.set(value); } public Map<String, Object> getSession() { return session.get(); } public Map<String, Object> getServletContext() { return servletContext.get(); } public Map<String, Object> getRequest() { return request.get(); } public static void destory() { request.remove(); session.remove(); servletContext.remove(); } } 一个接口,所有的Action类都必须要实现这个接口。 package com.zzq.velocity.core; import java.util.Map; public interface Action { public String execute() throws Exception; /** * 获取Velocity需要的Context数据 * @return Context */ public Map<String, Object> getContext(); } 最后就是这个web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>VelocityActionServlet</servlet-name> <servlet-class>com.zzq.velocity.core.VelocityActionServlet</servlet-class> <init-param> <param-name>properties</param-name> <param-value>/WEB-INF/velocity.properties</param-value> </init-param> <init-param> <param-name>templatePath</param-name> <param-value>/vm</param-value> </init-param> <load-on-startup>10</load-on-startup> </servlet> <servlet-mapping> <servlet-name>VelocityActionServlet</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app> 核心的东西就是这些,下面玩一下这个框架。 1、定义Action类 package com.velocity.test.action; import java.util.HashMap; import java.util.Map; import com.zzq.velocity.core.Action; import com.zzq.velocity.core.ServletActionContext; public class UserAction implements Action { private Map<String, Object> map = new HashMap<String, Object>(); public String execute() throws Exception { return "/login.vm"; } public String login() { String username = ServletActionContext.getRequset().getParameter("username"); String password = ServletActionContext.getRequset().getParameter("password"); User user = new User(); user.setUsername(username); user.setPassword(password); System.out.println(username); System.out.println(password); map.put("user", user); ServletActionContext.getSession().setAttribute("user", user); return "/login_success.vm"; } public String register() { String username = ServletActionContext.getRequset().getParameter("username"); String password = ServletActionContext.getRequset().getParameter("password"); System.out.println(username); System.out.println(password); return "/register_success.vm"; } public String registerInput() { return "/register.vm"; } public Map<String, Object> getContext() { return map; } } 2、在beans.properties加入 /user=com.velocity.test.action.UserAction 3、定义模板,放到WebRoot/vm/下(这个路径可以在web.xml中配) 引用 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h2>用户登录</h2> <form action="user.html" method="post"> <input type="hidden" name="method" value="login"> 用户名:<input name="username"><br> 密码:<input name="password" type="password"><br> <input type="submit" value="提交"> </form> </body> </html> 引用 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 登录成功!$user.username<br> session:$request.session.getAttribute('user').username </body> </html> 4、访问http://localhost:8080/Veloctiy/user.html 一看就知道 总之:这个就是现在闲着没意思编着玩的,缺少很多功能(如上传,参数类型装换,还有对整个框架的扩展如插件化等等),跟成型的MVC Framework没法发,但是如果有人力、时间、金钱,相信我们国人也会编出相当完美优雅的框架。 还有一个月就毕业了,回望过去,还是很向往自己的大学生活,面对现实只能勇敢的去面对。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-06-02
最后修改:2010-06-02
个人认为,花时间,并能够通过自己的手做出来,一定在过程中,学到了很多,感受了很多。这个是最宝贵的。其中结果并不一定很重要哦。
和脑海中思考、设计完全不同。 |
|
返回顶楼 | |
发表时间:2010-06-02
cloud21 写道 个人认为,花时间,并能够通过自己的手做出来,一定在过程中,学到了很多,感受了很多。这个是最宝贵的。其中结果并不一定很重要哦。
和脑海中思考、设计完全不同。 谢谢你的回复,你说很对,人都是在不断的吸取经验,其实结果并不重要,重要的是过程! |
|
返回顶楼 | |
发表时间:2010-06-02
为什么自己写的东西发上来却被评为“隐藏帖”,本意想把自己学习收获的成果分享一下,难道这还有什么错吗?评价“隐藏帖”的人,你们这样做让我很心寒!
|
|
返回顶楼 | |
发表时间:2010-06-02
晕了,为什么会被评隐藏贴
|
|
返回顶楼 | |
发表时间:2010-06-03
hui94781674 写道 晕了,为什么会被评隐藏贴
我已经无语,这个是我在JavaEye第一次在公共论坛上发帖,这以后还叫我怎么发帖啊。可能是说帖子有点长,但是毕竟代码都是自己写的,也没什么复杂的算法,用心的人很容易就能看出代码的用意,如果帖子哪块真有问题,评隐藏贴的人你可以指出来,也能让我知道究竟那块做的不对,哎~已经无语,不在沉默中爆发,就在沉默中灭亡! |
|
返回顶楼 | |
发表时间:2010-06-03
别急兄弟,不管怎么样,你的行动和专研精神是值得鼓励和支持的,我up你!希望你继续保持!
|
|
返回顶楼 | |
发表时间:2010-06-03
lihuan5120 写道 别急兄弟,不管怎么样,你的行动和专研精神是值得鼓励和支持的,我up你!希望你继续保持!
谢谢你的回复,我会继续努力的,男人要有骨气,越是打击你,就应该越有勇气敢去做——越挫越勇 |
|
返回顶楼 | |
发表时间:2010-06-03
LZ的钻研精神不错,值得肯定,JE的牛比较多,不入法眼也正常,不用太在意,人就是在评价中成长的
Velocity好久没有碰了,看了代码,让人怀念 希望LZ有更新帖 |
|
返回顶楼 | |
发表时间:2010-06-03
woming66 写道 为什么自己写的东西发上来却被评为“隐藏帖”,本意想把自己学习收获的成果分享一下,难道这还有什么错吗?评价“隐藏帖”的人,你们这样做让我很心寒!
写自己的博客、总结自己的知识,让别人去随意评论吧。 其实大可不必在意这些,自己专研知识、与人分享交流,最后得到进步,这才是王道。 |
|
返回顶楼 | |