`
woming66
  • 浏览: 58077 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

自己编写一个基于Velocity的MVC框架

    博客分类:
  • Java
阅读更多
公司留了作业(还有一个月毕业),让预习Velocity,在家呆着没意思,反正闲着也是闲着,看了VelocityViewServlet源码,感觉还可以,取其精华去其糟粕,自己写了一个基于Velocity的MVC框架,废话不多说了,直接进入正题。

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没法发,但是如果有人力、时间、金钱,相信我们国人也会编出相当完美优雅的框架。
还有一个月就毕业了,回望过去,还是很向往自己的大学生活,面对现实只能勇敢的去面对。
分享到:
评论
33 楼 javaboy2010 2012-12-26  
不错,还没毕业,写出如此代码,楼主很强啊! 向楼主学习!
32 楼 enjsky 2010-06-03  
Java企业级框架 .Net企业级框架
EfsFrame就是一套基于Ajax技术实现的优秀的Java/.Net企业级框架,简单+实用+高效+稳定
开源下载地址:http://www.efsframe.cn/
大量的框架设计文档,帮助学习系统框架设计原理
31 楼 woming66 2010-06-03  
xiangkun 写道
woming66 写道
为什么自己写的东西发上来却被评为“隐藏帖”,本意想把自己学习收获的成果分享一下,难道这还有什么错吗?评价“隐藏帖”的人,你们这样做让我很心寒!




慢慢就会习惯了.. 我都已经习惯了..JE上的大鸟们都是这样的!!

谢谢你的回复,呵呵 已经想通了 应有网友的话“自己专研知识、与人分享交流,最后得到进步,这才是王道”。
30 楼 xiangkun 2010-06-03  
woming66 写道
为什么自己写的东西发上来却被评为“隐藏帖”,本意想把自己学习收获的成果分享一下,难道这还有什么错吗?评价“隐藏帖”的人,你们这样做让我很心寒!




慢慢就会习惯了.. 我都已经习惯了..JE上的大鸟们都是这样的!!
29 楼 woming66 2010-06-03  
ilove2009 写道
不错,还没毕业就有这水平了。前途无量。

谢谢你的回复,我会继续努力的!
28 楼 ilove2009 2010-06-03  
不错,还没毕业就有这水平了。前途无量。
27 楼 woming66 2010-06-03  
jenlp520 写道
woming66 写道
jenlp520 写道
我插 je没有防重复提交的吗??

这块还没做呢,现在只是个架子,解决重复提交,我的想法是定义一个Velocity的宏,页面input的时候,载入宏(就是往session中弄个值,页面有个hidden),到提价的action中进行比对session和表单hidden的值。


其实我说的是javaeye 回帖的时候手一抖 回了2个

呵呵 人无完人 何况论坛系统了
26 楼 woming66 2010-06-03  
Norton_SdGromo 写道
Velocity我不太懂,但是只要肯动手就精神可嘉,不要太在意那些给隐藏贴的,继续努力~~

谢谢你的回复!我会努力的!
25 楼 jenlp520 2010-06-03  
woming66 写道
jenlp520 写道
我插 je没有防重复提交的吗??

这块还没做呢,现在只是个架子,解决重复提交,我的想法是定义一个Velocity的宏,页面input的时候,载入宏(就是往session中弄个值,页面有个hidden),到提价的action中进行比对session和表单hidden的值。


其实我说的是javaeye 回帖的时候手一抖 回了2个
24 楼 Norton_SdGromo 2010-06-03  
Velocity我不太懂,但是只要肯动手就精神可嘉,不要太在意那些给隐藏贴的,继续努力~~
23 楼 woming66 2010-06-03  
janrn 写道
看到此贴,眼睛一亮。LZ继续加油。
结果不是最重要的,代码也不是最重要的,设计思想才是最大的收获,以及研究的能力。
恭喜你,取得如此结果。

谢谢你的回复,愿我们一起努力,以后多多交流经验!
22 楼 janrn 2010-06-03  
看到此贴,眼睛一亮。LZ继续加油。
结果不是最重要的,代码也不是最重要的,设计思想才是最大的收获,以及研究的能力。
恭喜你,取得如此结果。
21 楼 woming66 2010-06-03  
<div class="quote_title">zhangshixi 写道</div>
<div class="quote_div">
<div class="quote_title">woming66 写道</div>
<div class="quote_div">
<div class="quote_title">zhangshixi 写道</div>
<div class="quote_div">
<div class="quote_title">woming66 写道</div>
<div class="quote_div">为什么自己写的东西发上来却被评为“隐藏帖”,本意想把自己学习收获的成果分享一下,难道这还有什么错吗?评价“隐藏帖”的人,你们这样做让我很心寒!</div>
<br>写自己的博客、总结自己的知识,让别人去随意评论吧。其实大可不必在意这些,自己专研知识、与人分享交流,最后得到进步,这才是王道。<br>
</div>
<br>谢谢你的评价。您说的很对!自己专研知识、与人分享交流,最后得到进步,这才是王道。望以后继续交流!</div>
<p><br>我觉得这也许就是我们的心态吧,抛开万千世界不谈,只说在这么一个小小的社区中,其实已经繁琐复杂了:<br>有的人以看文章、学知识为乐;<br>有的人以总结知识、写博客为乐;<br>有的人以与人分享、交流为乐;<br>有的人以盲目追求点击率、人气为乐;<br>有的人以高高在上、傲视群雄为乐;<br>有的人以打发无聊、寂寞为乐<br>......<br>那么我们想想自己又属于哪种人呢?<br>也许当您看透了这些,任何鼓励、打击、甚至被人BS,都是过眼云烟罢了。</p>
<p> </p>
</div>
<p> </p>
<p>说的好!</p>
20 楼 zhangshixi 2010-06-03  
<div class="quote_title">woming66 写道</div>
<div class="quote_div">
<div class="quote_title">zhangshixi 写道</div>
<div class="quote_div">
<div class="quote_title">woming66 写道</div>
<div class="quote_div">为什么自己写的东西发上来却被评为“隐藏帖”,本意想把自己学习收获的成果分享一下,难道这还有什么错吗?评价“隐藏帖”的人,你们这样做让我很心寒!</div>
<br>写自己的博客、总结自己的知识,让别人去随意评论吧。其实大可不必在意这些,自己专研知识、与人分享交流,最后得到进步,这才是王道。<br>
</div>
<br>谢谢你的评价。您说的很对!自己专研知识、与人分享交流,最后得到进步,这才是王道。望以后继续交流!</div>
<p><br>我觉得这也许就是我们的心态吧,抛开万千世界不谈,只说在这么一个小小的社区中,其实已经繁琐复杂了:<br>有的人以看文章、学知识为乐;<br>有的人以总结知识、写博客为乐;<br>有的人以与人分享、交流为乐;<br>有的人以盲目追求点击率、人气为乐;<br>有的人以高高在上、傲视群雄为乐;<br>有的人以打发无聊、寂寞为乐<br>......<br>那么我们想想自己又属于哪种人呢?<br>也许当您看透了这些,任何鼓励、打击、甚至被人BS,都是过眼云烟罢了。</p>
<p> </p>
19 楼 woming66 2010-06-03  
jenlp520 写道
我插 je没有防重复提交的吗??

这块还没做呢,现在只是个架子,解决重复提交,我的想法是定义一个Velocity的宏,页面input的时候,载入宏(就是往session中弄个值,页面有个hidden),到提价的action中进行比对session和表单hidden的值。
18 楼 woming66 2010-06-03  
jenlp520 写道
无论LZ这个东西写不好 都必须表扬下 是自己动手的 必定会有收获
至于那些评隐藏的 不用理他们 中国人有个特点就是 越是下层的人的在获得一点点权利后就会去欺负比他们更下层的人来获得快感

呵呵 谢谢你的回复。我会继续努力的!
17 楼 woming66 2010-06-03  
hardPass 写道
大概浏览量下,没仔细看,总归发现:
哦,不错哦!

我总觉着parse是个不可靠的东西——也许是错觉
不过如果能自己控制Velocity模板的缓存,细粒度的控制到页面片段的缓存,那就更好了

这个小弟弟,刚毕业就这么来塞,前途无量啊
不错,不错

谢谢你的回复!恩,这里的确有很多地方要改进,要重构的,随着今后的学习,我会继续完善它!
16 楼 jenlp520 2010-06-03  
我插 je没有防重复提交的吗??
15 楼 jenlp520 2010-06-03  
无论LZ这个东西写不好 都必须表扬下 是自己动手的 必定会有收获
至于那些评隐藏的 不用理他们 中国人有个特点就是 越是下层的人的在获得一点点权利后就会去欺负比他们更下层的人来获得快感
14 楼 jenlp520 2010-06-03  
无论LZ这个东西写不好 都必须表扬下 是自己动手的 必定会有收获
至于那些评隐藏的 不用理他们 中国人有个特点就是 越是下层的人的在获得一点点权利后就会去欺负比他们更下层的人来获得快感
Global site tag (gtag.js) - Google Analytics