文章目录
增强MVC框架
今天的内容是在上次的基础上进行的,如果不了解去我上一篇文章(关于mvc的简介)
思路:
一、首先我们要把子控制器Action的内容配置到xml文件里,然后通过反射来实例化子控制器
二、我们通过返回的结果码(也就是相当于我们forward的一个属性值),通过建模和解析找到action里的forward里面的属性redirect来确认它的转发类型,来进行统一转发。
三、增强我们的子控制器,也就是把我们所有的方法全部放进一个类中,这个类来实现我们的子控制器接口,然后通过我们传过来的方法和反射动态调用方法。
四、写一个ModelDriver泛型类接口,通过这个泛型传入对象,然后通过反射来给对象的属性赋值。
五、通过配置web.xml和代码判断,来使得框架的配置文件可变
所需jar包4个(前面两个可以不用,可以自己写底层的反射代码)
还要导入我们之前对文件建模和解析的类
ConfigModel
public class ConfigModel {
private Map<String, ActionModel> acmap=new HashMap<>();
public void push(ActionModel actionmodel) {
acmap.put(actionmodel.getPath(), actionmodel);
}
public ActionModel pop(String path) {
return acmap.get(path);
}
}
ActionModel
public class ActionModel {
private String path;
private String type;
private Map<String, ForwardModel> fMap=new HashMap<>();
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void push(ForwardModel forwardmodel) {
fMap.put(forwardmodel.getName(),forwardmodel);
}
public ForwardModel pop(String name) {
return fMap.get(name);
}
}
ForwardModel
public class ForwardModel {
private String name;
private String path;
private boolean redirect;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public boolean isRedirect() {
return redirect;
}
public void setRedirect(boolean redirect) {
this.redirect = redirect;
}
}
ConfigModelFatory文件解析工厂
public class ConfigModelFatory {
public static ConfigModel build() throws Exception {
return build("config.xml");
}
public static ConfigModel build(String string) throws Exception {
ConfigModel configmodel=new ConfigModel();
InputStream in = ConfigModelFatory.class.getResourceAsStream("config.xml");
SAXReader reader=new SAXReader();
Document doc = reader.read(in);
ActionModel actionmodel=null;
ForwardModel forwardmodel=null;
List<Element> actionEles = doc.selectNodes("/config/action");
for (Element actionEle : actionEles) {
actionmodel=new ActionModel();
//接下来需要往actionModel中填充内容
actionmodel.setPath(actionEle.attributeValue("path"));
actionmodel.setType(actionEle.attributeValue("type"));
//拿到foward
List<Element> forword = actionEle.selectNodes("forward");
for (Element forwardEle : forword) {
forwardmodel=new ForwardModel();
//往forwardModel中填充内容
forwardmodel.setName(forwardEle.attributeValue("name"));
forwardmodel.setPath(forwardEle.attributeValue("path"));
forwardmodel.setRedirect(!"false".equals(forwardEle.attributeValue("redirect")));
actionmodel.push(forwardmodel);
}
configmodel.push(actionmodel);//调用存值方法
}
return configmodel;
}
}
主控制器DispatcherServlet
/**
* 主控制器
* @author 86135
*
*/
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = -7094025920085803724L;//版本号
private ConfigModel configModel = null;//配置文件
//初始化方法
public void init() {
try {
//将原来的读取框架的默认配置文件转变成读取可配置路径的配置文件
String xmlPath = this.getInitParameter("xmlPath");
if(xmlPath == null || "".equals(xmlPath)) {
System.out.println(xmlPath+"qqq");
configModel = ConfigModelFatory.build();
}
else {
System.out.println(xmlPath+"as");
configModel = ConfigModelFatory.build(xmlPath);
}
} 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 url = req.getRequestURI();//Mvc/xxx.action
url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
//根据路径获取action的模型
ActionModel actionModel = configModel.pop(url);
if(actionModel==null) {
throw new RuntimeException("你没有配置对应的子控制器Action!!!");
}
try {
//原来子控制器的来源是map集合,这样的话子控制器被写死再map容器中,代码不够灵活
//现在将子控制器配置方式存放再config.xml中,未来可以通过改变config.xml中的内容
//随意给中央控制器添加子控制器
Action action = (Action)Class.forName(actionModel.getType()).newInstance();
// 调用模型驱动接口,获取所需要操作的实体类,然后将jsp传递过来的参数,封装到实体类中
if(action instanceof ModelDriver) {
ModelDriver modelDriver=(ModelDriver)action;
Object model = modelDriver.getModel();
BeanUtils.populate(model, req.getParameterMap());
//这是上面方法实现的底层所有代码
// Map<String, String[]> map = req.getParameterMap();
// for (Entry<String, String[]> entry : map.entrySet()) {
// //可以获取到类对应的属性bname,获取到类所对应的属性值
// if(!entry.getKey().equals("methodName")) {
// Field field= model.getClass().getDeclaredField(entry.getKey());
// field.setAccessible(true);
// field.set(model, req.getParameter(entry.getKey()));
// }
// }
}
// 每个子控制器,都需要对结果进行对应的处理,要么重定向,要么转发,代码重复量较大
// 针对于这一现象,将其交给配置文件来处理
// 调用了增强版的子控制器来处理业务逻辑
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 | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Action
/**
* 子控制器
* 专门用来处理业务逻辑
* @author 86135
*
*/
public interface Action {
String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException ;
}
ModelDriver模型驱动接口
/**
* 模型驱动接口
* 是用来处理jsp页面传递过来的参数,
* 将所有的参数自动封装到实体类T中
* @author 86135
*
* @param <T>
*/
public interface ModelDriver<T> {
T getModel();
}
ActionSupport,处理所有业务的增强的子控制器
/**
* 之前的Action只能处理一个实体类的业务
*
* 现在这个是增加版的子控制器
* 凡是这个实体类的操作,对应方法都可以写在当前增强版的子控制器来完成
* @author 86135
*
*/
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 | SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return code;
}
}
config.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/cal" type="com.xy.web.CalAction">
<forward name="calRes" path="/calRes.jsp" redirect="false" />
</action>
</config>
如果我们改变了默认的配置文件,而配置文件又不对的话就会报一个错误,这个错误是我们自己定义的
以及最后我们要改变配置文件所用到的web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>Mvc</display-name>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.xy.framework.DispatcherServlet</servlet-class>
<init-param>
<param-name>xmlPath</param-name>
<param-value>/mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
最后我们全部加强完之后,看看我们的计算器还能用吗
我们的jsp文件cal.jsp
<title>Insert title here</title>
<script type="text/javascript">
function doSub(value){
if(value==1){
calForm.methodName.value="add";
}
else if(value==2){
calForm.methodName.value="del";
}
else if(value==3){
calForm.methodName.value="chen";
}
else{
calForm.methodName.value="chu";
}
calForm.submit();
}
</script>
</head>
<body>
<form id="claForm" name="calForm" method="post" action="${pageContext.request.contextPath}/cal.action">
num1:<input type="text" name="num1" /><br/>
num2:<input type="text" name="num2" /><br/>
<input type="hidden" name="methodName" />
<input type="button" onclick="doSub(1)" value="+" />
<input type="button" onclick="doSub(2)" value="-" />
<input type="button" onclick="doSub(3)" value="x" />
<input type="button" onclick="doSub(4)" value="/" />
</form>
</body>
calRes.jsp
<title>Insert title here</title>
</head>
<body>
结果:${res}
</body>
结果为:
今天对mvc的增加就算是结束了。