通过XML对自定义mvc框架进行增强
这是我自定义MVC工作原理【一】的案例,我们来进行有效改造:
1 将Action的信息配置到xml(反射实例化)
原来是子控制器的来源是Map集合,这样的话子控制器会被写死在Map容器中,代码不够灵活,现在将子控器以配置的方式存放在config.xml中,未来可以通过改变config.xml中的内容随意给中央控制器添加子控制器
//主控制器
public class DispatcherServlet extends HttpServlet{
// private Map<String, Action> actionMap = new HashMap<>();
private ConfigModel configModel = null;
public void init() {
// actionMap.put("/addCal", new AddCalAction());
// actionMap.put("/delCal", new DelCalAction());
// actionMap.put("/mulCal", new MulCalAction());
// actionMap.put("/divCal", new DivCalAction());
try {
configModel = ConfigModelFactory.build();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
init();
String uri = req.getRequestURI();
uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));
// Action action = actionMap.get(uri);
// action.execute(req, resp);
ActionModel actionModel = configModel.pop(uri);
if(actionModel==null) {
throw new RuntimeException("你没有拍照对应的子控制器Action");
}
String type = actionModel.getType();
try {
Action action = (Action)Class.forName(type).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2 通过结果码控制页面的跳转
每个子控制器,都需要对结果进行对应的处理,要么转发,要么重定向,代码重复量较大,针对于这一现象,将其交给配置文件来处理
//子控制器:处理业务逻辑
public interface Action {
//void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException ;
String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException ;
}
//主控制器
public class DispatcherServlet extends HttpServlet{
// private Map<String, Action> actionMap = new HashMap<>();
private ConfigModel configModel = null;
public void init() {
// actionMap.put("/addCal", new AddCalAction());
// actionMap.put("/delCal", new DelCalAction());
// actionMap.put("/mulCal", new MulCalAction());
// actionMap.put("/divCal", new DivCalAction());
try {
configModel = ConfigModelFactory.build();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
init();
String uri = req.getRequestURI();
uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));
// Action action = actionMap.get(uri);
// action.execute(req, resp);
ActionModel actionModel = configModel.pop(uri);
if(actionModel==null) {
throw new RuntimeException("你没有配置对应的子控制器Action");
}
String type = actionModel.getType();
try {
Action action = (Action)Class.forName(type).newInstance();
String code = action.execute(req, resp);
ForwardModel forwardModel = actionModel.pop(code);
if(forwardModel==null) {
throw new RuntimeException("你没有配置对应的子控制器Action的处理方式forward");
}
String jspPath = forwardModel.getPath();
if(forwardModel.isRedirect()) {
resp.sendRedirect(req.getContextPath()+jspPath);
}else {
req.getRequestDispatcher(jspPath).forward(req, resp);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
在xml中这样配置:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/addCal" type="com.web.AddCalAction">
<forward name="calRes" path="/calRes.jsp" redirect="false" />
</action>
<action path="/delCal" type="com.web.DelCalAction">
<forward name="calRes" path="/calRes.jsp" redirect="false" />
</action>
<action path="/mulCal" type="com.web.MulCalAction">
<forward name="calRes" path="/calRes.jsp" redirect="false" />
</action>
<action path="/divCal" type="com.web.DivCalAction">
<forward name="calRes" path="/calRes.jsp" redirect="false" />
</action>
</config>
3 将一组相关的操作放到一个Action中(反射调用方法)
public class ActionSupport implements Action{
@Override
public final String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String methodName = req.getParameter("methodName");
String code = null;
try {
Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
method.setAccessible(true);
//具体调用了自己所写的子控制器中的方法来处理浏览器请求
code = (String)method.invoke(this, req, resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return code;
}
}
简化后,之前的AddCalAction,DelCalAction,MulCalAction,DivCalAction都不用了,只需要用CalAction ,所有操作写在这个类里面:
public class CalAction extends ActionSupport{
public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String num1 = req.getParameter("num1");
String num2 = req.getParameter("num2");
req.setAttribute("res", Integer.valueOf(num1)+Integer.valueOf(num2));
return "calRes";
}
public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String num1 = req.getParameter("num1");
String num2 = req.getParameter("num2");
req.setAttribute("res", Integer.valueOf(num1)-Integer.valueOf(num2));
return "calRes";
}
public String mul(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String num1 = req.getParameter("num1");
String num2 = req.getParameter("num2");
req.setAttribute("res", Integer.valueOf(num1)*Integer.valueOf(num2));
return "calRes";
}
public String div(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String num1 = req.getParameter("num1");
String num2 = req.getParameter("num2");
req.setAttribute("res", Integer.valueOf(num1)/Integer.valueOf(num2));
return "calRes";
}
}
然后在jsp中改写一下:
简化xml中:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/cal" type="com.web.CalAction">
<forward name="calRes" path="/calRes.jsp" redirect="false" />
</action>
</config>
4 利用ModelDriver接口对Java对象进行赋值(反射读写方法)
/**
* 模型驱动接口
* 用来处理jsp页面传来的参数
* 将所有的参数自动封装到实体类T中
* @author lenovo
*
* @param <T>
*/
public interface ModelDriven<T> {
T getModel();
}
public class CalAction extends ActionSupport implements ModelDriven<Cal>{
private Cal cal = new Cal();
public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("res", Integer.valueOf(cal.getNum1())+Integer.valueOf(cal.getNum2()));
return "calRes";
}
public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("res", Integer.valueOf(cal.getNum1())-Integer.valueOf(cal.getNum2()));
return "calRes";
}
public String mul(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("res", Integer.valueOf(cal.getNum1())*Integer.valueOf(cal.getNum2()));
return "calRes";
}
public String div(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("res", Integer.valueOf(cal.getNum1())/Integer.valueOf(cal.getNum2()));
return "calRes";
}
@Override
public Cal getModel() {
// TODO Auto-generated method stub
return cal;
}
}
然后在主控制器中加上这些代码:
//调用模型驱动接口获取所要操作的实体类,然后将jsp传递过来的参数封装到实体类中;
if(action instanceof ModelDriven) {
ModelDriven modelDriven =(ModelDriven)action;
Object model = modelDriven.getModel();
// 将所有的参数自动封装到实体类T中
BeanUtils.populate(model, req.getParameterMap());
}
5 使得框架的配置文件可变
在主控制器中把init()方法改写一下:
public void init() {
try {
//将原有的读取框架的默认配置文件转变成读取可配置路径的配置文件
String xmlPath = this.getInitParameter("xmlPath");
if(xmlPath==null||"".equals(xmlPath)) {
configModel = ConfigModelFactory.build();
}else {
configModel = ConfigModelFactory.build(xmlPath);
}
} catch (Exception e) {
e.printStackTrace();
}
}
假如我有另一个mvc.xml: