JAVAWEB学习(12) - 实现一个简单的MVC框架

实现一个简单的MVC框架

1. 目标

SmartMVC核心是一个通用的控制器(DispatcherServlet)。利用SmartMVC,我们在开发一个web应用时,只需要添加相应的配置,通过该控制器就可以调用相应的模型或者视图。也就是说,只需要写模型和视图,不再需要写控制器了。

2. 架构

smartmvc

3. 开发步骤

1. 创建一个Maven工程(smartmvc)

项目结构如下:

目录

2. 导包
<dependencies>
	<dependency>
		<groupId>dom4j</groupId>
		<artifactId>dom4j</artifactId>
		<version>1.6.1</version>
	</dependency>
</dependencies>
3. 添加一个JSP(/WEB-INF/hello.jsp)
<%@ page pageEncoding="utf-8" 
contentType="text/html; charset=utf-8" %>
<html>
	<head></head>
	<body style="font-size:30px;">
		Hello SmartMVC!
	</body>
</html>
4. 在base.annotation包下添加一个java注解(@RequestMapping)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
	public String value();
}
5. 在demo包下添加HelloController类(处理器)
//该类方法前添加@RequestMapping注解(指定请求路径)
//方法返回值是一个字符串(即视图名)
public class HelloController {

@RequestMapping("/hello.do")
public String hello(){
	System.out.println("HelloController的hello方法");
	return "hello";
 }
}
6. 在resources文件夹下添加smart-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<!-- 配置处理器:
			class属性用于指定处理器类名。
	 -->
	<bean class="demo.HelloController"/>
	<bean class="demo.LoginController"/>
</beans>
7. 在base.web包下添加DispatcherServlet
/**
在初始化方法里,读取配置文件中的处理器类名,将处理器实例化,
然后将处理器实例交给HandlerMapping来处理。
*/
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

private HandlerMapping handlerMapping;

@Override
/**
 * 读取配置文件(smartmvc.xml)的内容,将所有
 * 处理器实例化,然后将这些处理器实例交给
 * HandlerMapping来处理。
 * 注:
 * 	  HandlerMapping负责建立请求路径与处理器的
 * 对应关系。
 */
public void init() throws ServletException {
	//读取配置文件位置及文件名
	String configLocation = getServletConfig().getInitParameter("configLocation");
	
	SAXReader sax = new SAXReader();
	
	InputStream in = getClass().getClassLoader().getResourceAsStream(configLocation);
	
	try {
		/*
		 * 利用dom4j读取配置文件的内容,
		 * SAXReader的read方法的返回值可以
		 * 想像一棵树,我们可以从根节点开始,
		 * 一层一层遍历。
		 */
		Document doc = sax.read(in);
		//找到根节点
		Element root = doc.getRootElement();
		//找出根节点的所有子节点
		List<Element> elements = root.elements();
		List beans = new ArrayList();
		//遍历子节点,读取处理器类名
		for(Element ele : elements){
			String className = ele.attributeValue("class");
			System.out.println("className:" + className);
			//将处理器实例化
			Object bean = Class.forName(className).newInstance();
			beans.add(bean);
		}
		System.out.println("beans:" + beans);
		
		//将处理器实例交给HandlerMapping来处理
		handlerMapping  = new HandlerMapping();
		handlerMapping.process(beans);
		
	} catch (Exception e) {
		e.printStackTrace();
		throw new ServletException(e);
	}
}
8. 配置web.xml文件
<servlet>
	<servlet-name>DispatcherServlet</servlet-name>
	<servlet-class>base.web.DispatcherServlet</servlet-class>
	<!--
		指定配置文件的位置及文件名 
 	-->
	<init-param>
		<param-name>configLocation</param-name>
		<param-value>smart-mvc.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>DispatcherServlet</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>
9. 在base.common包下添加Handler类
public class Handler {
	private Method method;
	private Object obj;
	
	public Handler(Method method, Object obj) {
		this.method = method;
		this.obj = obj;
	}
	
	public Method getMethod() {
		return method;
	}
	public void setMethod(Method method) {
		this.method = method;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
}
10. 在base.common包下添加HandlerMapping类(映射处理器)
public class HandlerMapping {

//mappings用于存放请求路径与处理器的对应关系
private Map<String,Handler> mappings = 
		new HashMap<String,Handler>();

/**
 * 依据请求路径返回Handler对象。
 * 注:
 *   Handler对象封装了处理器对象及方法对象,
 *  方便利用java反射来调用处理器的方法。
 */
public Handler getHandler(String path){
	return mappings.get(path);
}

public void process(List beans) {
	for(Object bean: beans){
		//获得Class对象
		Class clazz = bean.getClass();
		//获得所有方法
		Method[] methods = clazz.getDeclaredMethods();
		//遍历所有方法
		for(Method mh : methods){
			//获得@RequestMapping注解
			RequestMapping rm = mh.getDeclaredAnnotation(RequestMapping.class);
			//获得请求路径
			String path = rm.value();
			//存放请求路径与处理器的对应关系
			mappings.put(path, new Handler(mh,bean));
		}
		
	}
	System.out.println("mappings:" + mappings);
	}
}

至此,一个简单的MVC框架就设计完成了,最后附上设计图:

s1

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个非常简单MVC框架实现了类似Spring MVC的基本功能。 1、包括自动扫描绑定映射路径,只要在web.xml中指定扫描包,系统启动后会将请求url绑定到指定的处理方法上。如: 在web.xml中定义如下: <context-param> <param-name>ScanPackage</param-name> <param-value>com.mvc.controller</param-value> </context-param> 容器在启动时候,会将com.mvc.controller下所有映射路径绑定处理方法上,假如在扫描包中定义下列类: import javax.imageio.ImageIO; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.hxw.simple.light.mvc.annotation.MappingMethodAnnotation; import com.hxw.simple.light.mvc.view.SimpleModelView; import com.mvc.verification.VerificationCode; public class LoginController { @MappingMethodAnnotation(mappingMethod = "/login.do") public String login(HttpServletRequest request, HttpServletResponse response) { return "login/main"; } @MappingMethodAnnotation(mappingMethod = "/loginvm.do") public SimpleModelView loginView(HttpServletRequest request, HttpServletResponse response) { SimpleModelView mv = new SimpleModelView("login/mainmv"); Map<String, String> m = new HashMap<String, String>(); m.put("beij", "北京"); m.put("sha", "上海"); m.put("nanj", "南京"); mv.setAttribute("city", m); return mv; } @MappingMethodAnnotation(mappingMethod = "/Verify.do") public void service(HttpServletRequest arg0, HttpServletResponse arg1) throws IOException { HttpServletRequest request = (HttpServletRequest) arg0; HttpServletResponse response = (HttpServletResponse) arg1; response.setContentType("image/jpeg"); response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); VerificationCode vCode = new VerificationCode(); BufferedImage bufferImage = vCode.getImageData(); HttpSession session = request.getSession(); response.addCookie(new Cookie("JSSESIONID", session.getId())); ServletOutputStream responseOutputStream = response.getOutputStream(); ImageIO.write(bufferImage, "JPEG", responseOutputStream); responseOutputStream.flush(); responseOutputStream.close(); } } 那么在接到url请求如:http://localhost:8080/TestSimpleMVC/loginvm.do 会调用指定的方法处理。 2、支持视图定义,在web.xml定义了视图路径后: <servlet> <servlet-name>DelegateForwardServlet</servlet-name> <servlet-class>com.hxw.simple.light.mvc.servlet.DelegateForwardServlet</servlet-class> <init-param> <param-name>prefix</param-name> <param-value>/WEB-INF/view/</param-value> </init-param> <init-param> <param-name>suffix</param-name> <param-value>.jsp</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>DelegateForwardServlet</servlet-name> <url-pattern>/SYS_FORWARD_URL.fo</url-pattern> </servlet-mapping> 只需在执行完方法后,返回字符串:如return "login/main"就会跳转到指定视图,还可以在视图中用EL表单式访问modelview数据,例子如: SimpleModelView mv = new SimpleModelView("login/mainmv"); Map<String, String> m = new HashMap<String, String>(); m.put("beij", "北京"); m.put("sha", "上海"); m.put("nanj", "南京"); mv.setAttribute("city", m); return mv; 3、支持数据参数自动绑定如: @ParamAttribute(type = ParamaAttributeType.REQUEST, key = "userPassword") String s, @ParamAttribute(type = ParamaAttributeType.SESSION, key = "11212") String s1, @ParamAttribute(type = ParamaAttributeType.SERVLETCONTEXT, key = "32312") String s2, @ParamAttribute(type = ParamaAttributeType.REQUEST, key = "userNames") String[] s3 系统根据参数指定的范围,这指定范围内赋值到参数上,你还可以直接使用javabean做参数绑定,如: public class User extends PaginatedHelper { private static final long serialVersionUID = -8225389551152428829L; private String userName; private String userPassword; public User() { super(); } public User(String userName, String userPassword) { super(); this.userName = userName; this.userPassword = userPassword; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPassword() { return userPassword; } public void setUserPassword(String userPassword) { this.userPassword = userPassword; } 在方法上带上 Uer user后,属性名称相同的数据就会赋值到javabean上。不必再使用繁琐的user.setUserName(request.getParameter("userName")); 3、简便的jdbc操作 有查询模板QueryTemplate,命名查询NamedQueryTemplate及bean作为参数的BeanQueryTemplate等。支持返回javabean类型,javabean列表, MAP类型,map列表类型,统计结果queryForInt等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值