模拟SpringMVC写SmartMVC小型框架并计算BMI指数

1、SmartMVC是一个web mvc框架,实现了一个通用的控制器(DispatcherServlet),
利用该框架可以开发基于MVC架构的web应用。使用该框架,只需要写视图
和模型。
2、SmartMVC的主要组件及关系在这里插入图片描述
3、SmartMVC执行流程
在这里插入图片描述
新建一个Maven工程,jar该为war,生成web.xml文件,为工程添加Tomcat服务器
4、导入依赖的包:在项目的pom.xml文件中添加以下代码

<dependency>
	<groupId>dom4j</groupId>
	<artifactId>dom4j</artifactId>
	<version>1.6.1</version>
</dependency>

5、指定配置文件的位置及名称和配置启动加载,在项目的web.xml文件中的标签之前添加以下代码

<!-- 指定配置文件的位置及名称 -->
<!-- 可以使用初始化参数来指定配置文件的路径及文件名(以便读取配置文件不用写死)-->
<init-param>
		<param-name>configLocation</param-name>
		<param-value>smartmvc.xml</param-value>
</init-param>		
<!-- 配置启动加载
	 即容器启动之后,会立即创建该servlet的实例, 接下来,会调用该实例的init方法、
	 参数是一个大于等于零的整数,越小,优先级越高,即有限创建该实例    -->
<load-on-startup>1</load-on-startup>

6、SmartMVC核心类
RequestMapping.java类

@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
	String value();
}

Handler.java类

/**
 * 为了方便利用Java反射机制去调用处理器的方法而设计的一个辅助类。
 */
public class Handler {
	//method:处理器方法对应的Method对象
	private Method method;
	//obj:处理器实例
	private Object 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;
	}	
	}

HandlerMapping.java类

/**
 * 映射处理器类:负责提供请求路径与处理器的对应关系:比如:"/hello.do"这个请求应该
 * 							有HelloController 的hello方法来处理。
 */
public class HandlerMapping {
	/*
	 * maps:存放请求路径与处理器的对应关系。
	 * 注:
	 * 		Handler封装了处理器实例与方法对象, 这样方便利用Java反射去调用处理器方法。
	 */
	private Map<String, Handler> maps=new HashMap<String, Handler>();
	
	/*
	 * 依据请求路径返回Handler对象。
	 * @param path 请求路径,比如"/hello.do"
	 * @return Handler 对象(封装有处理器实例及方法)
	 */
	public Handler getHandler(String path) {
		return maps.get(path);
	}
	
	/*
	 * 负责建立请求路劲与处理器的对应关系
	 * @param beans 处理器实例组成的集合
	 */
	public void process(List beans) {
		for (Object bean : beans) {
			//获得Class对象
			Class clazz=bean.getClass();
			//获得处理器的所有方法
			Method[] methods=clazz.getDeclaredMethods();
			//遍历所有方法
			for (Method method : methods) {
				//获得加在方法前的@RequestMapping
				RequestMapping rm=method.getDeclaredAnnotation(RequestMapping.class);
				//获得请求路径
				String path=rm.value();
				System.out.println("path:"+path);
				/*
				 * 以请求路径作为key,以处理实例及方法
				 * 的封装(Handler)作为value,将这个
				 * 对应关系存放到maps里面。
				 */
				Handler handler=new Handler();
				handler.setMethod(method);
				handler.setObj(bean);
				maps.put(path, handler);
			}
		}
		System.out.println("maps:"+maps);
	}	
}

DispatcherServlet.java类

public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;  
	private HandlerMapping handlerMapping;
	public DispatcherServlet() {
		System.out.println("DispatcherServlet's constructor");
	}
	@Override
	/**
	 * 读取smartmvc配置文件,依据读取到的类名创建处理器对象,然后偶将处理器对对象交给
	 * HandlerMapping来处理。
	 */
	public void init() throws ServletException {
		SAXReader saxReader=new SAXReader();
		//读取配置文件的位置及文件名
		String configLocation = getInitParameter("configLocation");
		/*
		 * 利用类加载器(ClassLoader)提供的方法来获得一个输入流(该流只需要读取的配置文件)
		 */
		InputStream in=getClass().getClassLoader().getResourceAsStream(configLocation);
		try {
			//解析配置文件
			Document doc=saxReader.read(in);
			//获取根元素
			Element root=doc.getRootElement();
			//beans集合用于存放处理器对象
			List beans=new ArrayList();
			//获取根元素下面的所有子元素
			List<Element> elements=root.elements();
			//遍历所有子元素
			for (Element element : elements) {
				//获得处理器类名
				String className=element.attributeValue("class");
				System.out.println("className:"+className);
				//将处理器实例化(即创建处理器对象)
				Object obj=Class.forName(className).newInstance();
				beans.add(obj);
			}
			System.out.println("beans:"+beans);
			
			/*
			 * 创建HandlerMapping对象,然后将
			 * 处理器实例组成的集合交给该对象
			 * 进行处理
			 */
			handlerMapping=new HandlerMapping();
			handlerMapping.process(beans);					
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("读取配置文件失败");
		}
	}		
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//获取请求路径
		String uri=request.getRequestURI();
		//获取应用名
		String contextPath=request.getContextPath();
		//将请求资源中的应用名除掉
		String path=uri.substring(contextPath.length());
		System.out.println("path:"+path);
		
		/*
		 * 以请求路径(path)作为参数,调用HandlerMapping对象方法,获得与该请求路径对应的Handler对象,
		 * 接下来,就可以通过Handler对象来调用处理器的方法
		 */
		Handler handler=handlerMapping.getHandler(path);
		System.out.println("handler:"+handler);
		if(handler==null) {
			response.sendError(404);
			System.out.println("没有对应的处理器");
			return;
		}
		//利用Handler对象来调用处理器的方法
		Method method=handler.getMethod();
		Object obj=handler.getObj();
		Object rv=null;
		try {
			/*
			 * 先看处理器的方法带不带参, 如果带有参数(暂时只支持两种类型的参数,
			 *  分别是HttpServletRequest和HttpServletResponse), 则按照带有参数的方式调用,
			 * 即method.invoke(obj,params)
			 */
			//获得处理器方法的参数类型信息
			Class[] types=method.getParameterTypes();
			if(types.length==0) {
				//处理器方法不带参
				rv=method.invoke(obj);
			}else {
				//params用于存放实际参数值
				Object[] params=new Object[types.length];
				//依据参数类型,进行相应的赋值
				for (int i = 0; i < types.length; i++) {
					if(types[i]==HttpServletRequest.class) {
						params[i]=request;
					}
					if(types[i]==HttpServletResponse.class) {
						params[i]=response;
					}
				}
				rv=method.invoke(obj, params);
			}
			
			//viewName:视图名
			String viewName=rv.toString();
			System.out.println("viewName:"+viewName);
			/*
			 * 处理视图名
			 * 默认转发到"/WEB-INF/"+视图名+".jsp", 如果视图名是以"redirect:"开头,则重定向
			 */
			if(viewName.startsWith("redirect:")) {
				//生成重定向地址
				String redirectPath=contextPath+"/"+viewName.substring("redirect:".length());
				//重定向
				response.sendRedirect(redirectPath);
			}else {
				//转发
				String forwardPath="/WEB-INF/"+viewName+".jsp";
				request.getRequestDispatcher(forwardPath).forward(request, response);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
}

计算bmi指数实现
BmiController.java类

public class BmiController {
	@RequestMapping("/toBmi.do")
	public String toBmi() {
		System.out.println("BmiController's toBmi()");
		return "bmi";
	}
	@RequestMapping("/bmi.do")
	public String bmi(HttpServletRequest request) {
		System.out.println("BmiController's bmi()");
		//读取升高、体重
		String height=request.getParameter("height");
		String weight=request.getParameter("weight");
		System.out.println("height:"+height+"weight:"+weight);
		BMIService bService=new BMIService();
		String status=bService.bmi(Double.parseDouble(height), Double.parseDouble(weight));
		//转发
		request.setAttribute("status", status);
		return "view";
	}
}

BMIService.java类

public class BMIService {
	public String bmi(double height,double weight) {
		String status="正常";
		double bmi=weight/height/height;
		if(bmi<19) {
			status="过轻";
		}
		if(bmi>25) {
			status="过重";
		}
		return status;
	}

7、配置BmiController组件:新建一个以xml结尾的配置文件,添加以下内容:

<beans>
	<!-- 配置处理器 -->
	<bean class="包名+类名"/>
</beans>

8、在项目中的WEB-INF文件夹中建对应的jsp文件
bmi.jsp

<%@ page contentType="text/html; charset=utf-8"  pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body style="font-size:30px;">
  <form action="bmi.do" method="post">
    <fieldset>
      <legend>计算BMI指数</legend>
      体重(公斤):<input name="weight"/><br/>
     身高(米):<input name="height"/><br/>
           <input type="submit" value="确定"/>
    </fieldset>
  </form>
</body>
</html>

view.jsp

<%@ page contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Insert title here</title>
</head>
<body style="font-size:30px;">
  		体重状况:${status}
</body>
</html>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值