目录
DispatcherAction extends Action
参数名:methodName:add/minus/mul/div
3.创建CalAction类(CalAction提供一组加减乘除的方法)
CalAction extends DispatcherAction
提供一组与execute方法的参数、返回值相同的方法,只有方法名不一样
简化调用:BeanUtils.populate(calBean, parameterMap);
一:博客重点
通过XML对自定义MVC框架进行3步增强
二:反射增强第一步:
1.config.xml建模
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config>
<!--config标签:可以包含0~N个action标签 -->
<config>
<action path="/helloAction" type="com.zking.mvc.action.HelloAction"/>
<action path="/addAction" type="com.zking.mvc.action.AddAction">
<forward path="/rs.jsp" redirect="false" name="success"/>
</action>
<action path="/calAction" type="com.zking.mvc.action.CalAction">
<forward path="/rs.jsp" redirect="false" name="success"/>
</action>
</config>
2.获取Action配置信息
//获取请求路径*.action 例如:/helloAction.action
String requestURL = req.getServletPath();
//获取请求路径名 * 例如:/helloAction
int start = requestURL.indexOf("/");
int end = requestURL.lastIndexOf(".");
String requestName = requestURL.substring(start, end);
//根据请求路径名获取对应的ActionModel建模对象(path和type)
ActionModel actionModel = this.findAction(requestName);
/**
* 根据请求路径名获取对应的ActionModel建模对象(path和type)
* path:请求路径名,例如:/helloAction
* type:对应子控制器类Action的全路径名,Class.forName
* @param requestName 请求路径名
* @return
*/
private ActionModel findAction(String requestName) {
ActionModel actionModel = configModel.get(requestName);
if(null==actionModel)
throw new RuntimeException("ActionModel不存在!!!");
return actionModel;
}
3.反射机制实例化Action子控制器
//根据ActionModel中的type属性实现子控制器类Action反射机制实例化
Action action = this.createAction(actionModel.getType());
/**
* 根据ActionModel中的type属性实现子控制器类Action反射机制实例化
* @param type 类的全路径名,例如:com.zking.xxx.action.HelloAction
* @return
*/
private Action createAction(String type) {
try {
//获取类对象(3种),此处使用Class.forName
Class cls = Class.forName(type);
//直接反射机制实例化子控制器类
return (Action) cls.newInstance();
} catch (Exception e) {
throw new RuntimeException("反射机制实例化Action子控制器类失败!");
}
}
4.将请求委托给子控制器处理并返回结果码
//将请求委托给具体的子控制器类Action去处理并返回请求结果码
String code = action.execute(req, resp);
5.根据返回结果码进行页面跳转(重定向/转发)
//根据请求结果码跳转页面(重定向和转发)
this.gotoPage(req, resp, code, actionModel);
/**
* 跳转页面(转发或者重定向)
* @param req
* @param resp
* @param code 请求结果码,对应config.xml中forward标签的name属性
* @param actionModel config.xml中action标签对应的建模实体类,其中包含了0~N个forward标签的建模实体类ForwardModel
* @throws ServletException
* @throws IOException
*/
private void gotoPage(HttpServletRequest req,HttpServletResponse resp,
String code,ActionModel actionModel) throws ServletException,IOException{
//判断结果码是否为空
if(null==code)
return;
//根据请求结果码获取对应的ForwardModel
ForwardModel forwardModel = actionModel.get(code);
//判断forwardModel是否为空
if(null==forwardModel)
throw new RuntimeException("ForwardModel不存在!!!");
//post和get的区别?
//重定向和转发的区别?
//1) 重定向地址栏改变,转发不变
//2) 重定向能重定向到外部资源,转发只能转发项目内部资源
//3) 重定向二次请求,转发一次请求
//4) 重定向一般存储到session或者application(不推荐);转发保存到request(推荐)
//根据forwardModel中的redirect属性判断跳转方式(重定向或者转发)
if(forwardModel.isRedirect())
resp.sendRedirect(req.getContextPath()+forwardModel.getPath());
else
req.getRequestDispatcher(forwardModel.getPath()).forward(req, resp);
}
三:反射增强第二步:
将一组相关的操作放到一个Action中(反射调用方法)
1.创建DispatcherAction类
DispatcherAction extends Action
2.根据请求参数获取方法名,利用反射机制调用方法
参数名:methodName:add/minus/mul/div
package com.zking.mvc.framework;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 反射调用方法,不做具体的核心业务逻辑处理
* @author Administrator
*
*/
public class DispatcherAction extends Action {
/**
* 反射调用具体的子控制器类Action中的方法
*/
@Override
public final String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
//1.获取请求方法名(要调用哪一个方法去完成具体的核心业务)
String methodName = req.getParameter("methodName");
//判断methodName是否为空
if(null==methodName) {
//获取请求参数集合Map
Map<String, String[]> params = req.getParameterMap();
//获取请求参数集合的键值对
Set<Entry<String,String[]>> entrySet = params.entrySet();
//循环遍历键值对
for (Entry<String, String[]> entry : entrySet) {
//获取Key,对应表单元素中的name属性
String key = entry.getKey();
//判断key中是否包含methodName:的请求参数名
if(key.indexOf("methodName:")==0) {
methodName=key.replace("methodName:", "");
break;
}
}
}
//2.获取类对象
Class cls = this.getClass();
//3.反射调用方法
Method method=cls.getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
//4.设置访问权限
method.setAccessible(true);
//5.执行方法并返回结果码
Object code = method.invoke(this, req,resp);
return null==code?null:code.toString();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("反射调用方法异常!");
}
}
}
3.创建CalAction类(CalAction提供一组加减乘除的方法)
CalAction extends DispatcherAction
提供一组与execute方法的参数、返回值相同的方法,只有方法名不一样
package com.zking.mvc.action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zking.mvc.entity.CalBean;
import com.zking.mvc.framework.DispatcherAction;
import com.zking.mvc.framework.DriverModel;
/**
* 做一件事情:XxxAction extends Action -> execute
* 做多件事情:XxxAction extends DispatcherAction
* 必须要传递一个参数叫做methodName
* 注:只要继承了DispatcherAction,则提供一组与execute相同的参数和返回值的方法,只有方法名不同
* @author Administrator
*
*/
public class CalAction extends DispatcherAction implements DriverModel<CalBean> {
//必须要在返回之前先完成实例化操作
private CalBean calBean=new CalBean();
@Override
public CalBean getModel() {
// TODO Auto-generated method stub
return calBean;
}
/**
* 加法
* @param req
* @param resp
* @return
* @throws ServletException
* @throws IOException
*/
public String add(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println(calBean);
/*int num1=Integer.parseInt(req.getParameter("num1"));
int num2=Integer.parseInt(req.getParameter("num2"));*/
int rs=calBean.getNum1()+calBean.getNum2();
req.setAttribute("rs", rs);
//req.getRequestDispatcher("/rs.jsp").forward(req, resp);
return "success";
}
/**
* 减法
* @param req
* @param resp
* @return
* @throws ServletException
* @throws IOException
*/
public String minus(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/*int num1=Integer.parseInt(req.getParameter("num1"));
int num2=Integer.parseInt(req.getParameter("num2"));*/
int rs=calBean.getNum1()-calBean.getNum2();
req.setAttribute("rs", rs);
//req.getRequestDispatcher("/rs.jsp").forward(req, resp);
return "success";
}
/**
* 乘法
* @param req
* @param resp
* @return
* @throws ServletException
* @throws IOException
*/
public String div(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/*int num1=Integer.parseInt(req.getParameter("num1"));
int num2=Integer.parseInt(req.getParameter("num2"));*/
int rs=calBean.getNum1()*calBean.getNum2();
req.setAttribute("rs", rs);
//req.getRequestDispatcher("/rs.jsp").forward(req, resp);
return "success";
}
/**
* 除法
* @param req
* @param resp
* @return
* @throws ServletException
* @throws IOException
*/
public String mod(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/*int num1=Integer.parseInt(req.getParameter("num1"));
int num2=Integer.parseInt(req.getParameter("num2"));*/
int rs=calBean.getNum1()/calBean.getNum2();
req.setAttribute("rs", rs);
//req.getRequestDispatcher("/rs.jsp").forward(req, resp);
return "success";
}
}
四、反射增强第三步:
利用ModelDriver接口对Java对象进行赋值(反射读写方法)
1.利用反射机制对Java对象进行属性赋值
简化调用:BeanUtils.populate(calBean, parameterMap);
//反射参数赋值
this.setParameters(req, action);
/**
* 反射参数赋值
* @param req
* @param action
*/
private void setParameters(HttpServletRequest req,Action action) {
//判断action子控制器类是否实现了DriverModel接口
if(action instanceof DriverModel) {
//强转
DriverModel dm=(DriverModel) action;
//获取DriverModel接口对应方法的返回值
Object model = dm.getModel();
//获取请求参数集合
Map<String, String[]> params = req.getParameterMap();
//通过第三方工具类完成反射参数赋值工作
try {
BeanUtils.populate(model, params);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.ModelDriver接口返回的对象不能为空
package com.zking.mvc.framework;
public interface DriverModel<T> {
public T getModel();
}
注:Action多例模式?因为Action的属性要用来接收参数