通过XML对自定义mvc框架进行增强
1 将Action的信息配置到xml(反射实例化)
原来子控制器的来源是map集合,这样的话子控制器会被写在map容器中,代码不够i灵活。现在将子控制器以配置的方式放在config.xml中,未来可以通过改变config.xml中的内容。随意给中央控制器添加子控制器
2 通过结果码控制页面的跳转
每个子控制器,都需要对结果进行对应的处理,也就是说要么转发,要么重定向,代码重复量较大针对于这一现象,将其交给配置文件来处理
3 将一组相关的操作放到一个Action中(反射调用方法
在同一个Action里面进行加减乘除, 提供一组与execute方法的参数、返回值相同的方法,只有方法名,和方法内容不一样的方法
4 利用ModelDriver接口对Java对象进行赋值(反射读写方法)
处理jsp页面传递过来的参数,将所有的参数自动封装到实体类T中
5 使得框架的配置文件可变
因为做项目时要调用多个架构,配置文件名可能重复,为了避免找不到配置文件路径的问题,所有我们需要使得框架的配置文件可变,也就是将原有的读取框架的默认配置文件转变成可配置路径的配置文件,先获取文件路径,再调用xml建模的方法。
configModel = ConfigModelFactory.newInstance();
String xmlPath = this.getInitParameter(“xmlPath”);
configModel = ConfigModelFactory.newInstance();
建议再新建一个放xml的文件夹,于src同级
下面就是具体代码:
**
* 自控制器
* 专门用来处理业务逻辑的
* @author tt
*
*/
public interface Action {
/**
* 处理代码的方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException ;
}
/**
* 主控制器
* @author tt
*
*/
public class DispatcherServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
// 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("/chuCal", new ChuCalAction());
// actionMap.put("/chengCal", new ChengCalAction());
try {
//将原有的读取框架的默认配置文件转变成可配置路径的配置文件
configModel = ConfigModelFactory.newInstance();
String xmlPath = this.getInitParameter("xmlPath");
if(xmlPath == null||"".equals(xmlPath)) {
configModel = ConfigModelFactory.newInstance();
}else {
configModel = ConfigModelFactory.newInstance(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();//T224_mvc/xxx.action
url = url.substring(url.lastIndexOf("/"),url.lastIndexOf("."));
// Action action = actionMap.get(url);
ActionModel actionModel = configModel.get(url);
if(actionModel==null) {
throw new RuntimeException("你没有配置对应的子控制器Action!!!");
}
try {
// 原来子控制器的来源是map集合,这样的话子控制器会被写在map容器中,代码不够i灵活
// 现在将子控制器以配置的方式放在config.xml中,未来可以通过改变config.xml中的内容
// 随意给中央控制器添加子控制器
Action action = (Action)Class.forName(actionModel.getType()).newInstance();
//调用模型驱动接口,获得所要操作的实体类,然后将jsp传递过来的参数封装到实体类中
if(action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven) action;
Object model = modelDriven.getModel();
// Map<String, String[]> map = req.getParameterMap();
// for(Map.Entry<String, String[]> entry:map.entrySet()) {
可以获取到类对应属性bname,获得到类所对应的属性值
// }
// Field field = model.getClass().getDeclaredField("bname");
// field.setAccessible(true);
// field.set(model, req.getParameter("bname"));
//将所有的参数自动封装到实体类T中
BeanUtils.populate(model, req.getParameterMap());
}
//每个子控制器,都需要对结果进行对应的处理,也就是说要么转发,要么重定向,代码重复量较大
//针对于这一现象,将其交给配置文件来处理
// 调用了增强版的子控制器来处理业务逻辑
String code = action.execute(req, resp);
ForwardModel forwardModel = actionModel.get(code);
if(forwardModel == null) {
throw new RuntimeException("你没有配置对应的子控制器Action的处理方式Forward!!!");
}
String jspPath = forwardModel.getPath();
if(forwardModel.getRedirect().equals("true")) {
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();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
/**
* 模型驱动接口
* 是用来处理jsp页面传递过来的参数,将所有的参数自动封装到实体类T中
* @author tt
*
* @param <T>
*/
public interface ModelDriven<T> {
T getModel();
}
/**
* 存放相关的操作放到一个Action中
* @author tt
*
*/
public class CalAction extends ActionSupport implements ModelDriven<Cal>{
private Cal cal = new Cal();
/**
* 进行加法操作的方法
* @param req
* @param resp
* @return
* @throws ServletException
* @throws IOException
*/
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(cal.getNum1())+ Integer.valueOf(cal.getNum2()));
// req.getRequestDispatcher("calRes.jsp").forward(req, resp);
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(cal.getNum1())- Integer.valueOf(cal.getNum2()));
// req.getRequestDispatcher("calRes.jsp").forward(req, resp);
return "calRes";//返回路经
}
@Override
public Cal getModel() {
// TODO Auto-generated method stub
return cal;//cal已经有值了,那边传过来了。
}
}
web.xml配置
<display-name>TT_mvc</display-name>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.tt.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文件
注:jsp文件和上一节的没什么改变,只是传的不是路径,而是方法名
</head>
<script type="text/javascript">
function doSub(val) {
if(val == 1){
/* calForm.action ="${pageContext.request.contextPath }/addCal.action"; */
calForm.methodName.value ="add";
}else if(val==2){
/* calForm.action ="${pageContext.request.contextPath }/delCal.action"; */
calForm.methodName.value ="del";
}
else if(val==3){
/* calForm.action ="${pageContext.request.contextPath }/chengCal.action"; */
calForm.methodName.value ="cheng";
}
else if(val==4){
/* calForm.action ="${pageContext.request.contextPath }/chuCal.action"; */
calForm.methodName.value ="chu";
}
calForm.submit();
}
</script>
<body>
<form id = "calForm" name="calForm" 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">
<button onclick="doSub(1)">+</button>
<button onclick="doSub(2)">-</button>
<button onclick="doSub(3)">*</button>
<button onclick="doSub(4)">/</button>
</form>
</body>
注意:记得导包。
xml建模代码
注:DispatcherServlet里面,actionModel一直为空,一直报你没有配置对应的子控制器Action!!!而你的代码没有问题,那么就是xml建模的代码有问题。
/**
* 用来描述action标签
* @author Administrator
*
*/
public class ActionModel implements Serializable{
private static final long serialVersionUID = 6145949994701469663L;
private Map<String, ForwardModel> forwardModels = new HashMap<String, ForwardModel>();
private String path;
private String type;
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 put(ForwardModel forwardModel){
forwardModels.put(forwardModel.getName(), forwardModel);
}
public ForwardModel get(String name){
return forwardModels.get(name);
}
}
/**
* 之前的Action只能处理一个实体类的一个业务
* 现在这个是增强版的子控制器
* 凡是这个实体列的操作,对应方法都可以写在当前增强版的子控制器来完成;
* @author tt
*
*/
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;
}
}
/**
* 用来描述config标签
* @author Administrator
*
*/
public class ConfigModel implements Serializable{
private static final long serialVersionUID = -2334963138078250952L;
private Map<String, ActionModel> actionModels = new HashMap<String, ActionModel>();
public void put(ActionModel actionModel){
actionModels.put(actionModel.getPath(), actionModel);
}
public ActionModel get(String name){
return actionModels.get(name);
}
}
/**
* 工厂模式
* @author tt
*
*/
public class ConfigModelFactory {
private ConfigModelFactory() {
}
private static ConfigModel configModel = null;
public static ConfigModel newInstance() throws Exception {
return newInstance("config.xml");
}
/**
* 工厂模式创建config建模对象
*
* @param path
* @return
* @throws Exception
*/
public static ConfigModel newInstance(String path) throws Exception {
if (null != configModel) {
return configModel;
}
ConfigModel configModel = new ConfigModel();
InputStream is = ConfigModelFactory.class.getResourceAsStream(path);
SAXReader saxReader = new SAXReader();
Document doc = saxReader.read(is);
List<Element> actionEleList = doc.selectNodes("/config/action");
ActionModel actionModel = null;
ForwardModel forwardModel = null;
for (Element actionEle : actionEleList) {
actionModel = new ActionModel();
actionModel.setPath(actionEle.attributeValue("path"));
actionModel.setType(actionEle.attributeValue("type"));
List<Element> forwordEleList = actionEle.selectNodes("forward");
for (Element forwordEle : forwordEleList) {
forwardModel = new ForwardModel();
forwardModel.setName(forwordEle.attributeValue("name"));
forwardModel.setPath(forwordEle.attributeValue("path"));
forwardModel.setRedirect(forwordEle.attributeValue("redirect"));
actionModel.put(forwardModel);
}
configModel.put(actionModel);
}
return configModel;
}
public static void main(String[] args) {
try {
ConfigModel configModel = ConfigModelFactory.newInstance();
ActionModel actionModel = configModel.get("/loginAction");
ForwardModel forwardModel = actionModel.get("failed");
System.out.println(actionModel.getType());
System.out.println(forwardModel.getPath());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 用来描述forward标签
* @author Administrator
*
*/
public class ForwardModel implements Serializable {
private static final long serialVersionUID = -8587690587750366756L;
private String name;
private String path;
private String 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 String getRedirect() {
return redirect;
}
public void setRedirect(String redirect) {
this.redirect = redirect;
}
}
//config.xml
<config>
<action path="/cal" type="com.tt.web.CalAction">
<forward name="calRes" path="/calRes.jsp" redirect="false" />
</action>
</config>