目录
一、前言
二、实现中央控制器动态加载存储子控制器
三、优化参数传递封装代码
四、优化方法执行结果转发||重定向
五、实现框架配置文件名可变
一、前言
继承上篇文章:自定义MVC(上)__Leaf1217的博客-CSDN博客
我们在上篇文章编写了自定义MVC框架,
但是却并不完善,这篇文章就是来接着完善我们自定义框架,
我们首先抛出今天要完善的几个目标点!
二、实现中央控制器动态加载存储子控制器
2.1 利用建模的知识编写好配置文件
这个建模的相关资料在我前面的文章:XML建模__Leaf1217的博客-CSDN博客
不会的可以先去参考一下再来噢~
这里就不重复放过多的资料了,直接把之前的config的相关类直接复制一份到当前MVC的包下。
就放上需要改动一点的XML文件吧:
这里吧action的path值改为了我们的测试MVC的实体类/Book,type改成请求的action全路径名。
2.2 封装configModel类并调用工厂的方法给他赋值我们先封装一个configModel属性:
private ConfigModel configModel;
然后调用工厂类ConfigModelFactory的方法给模型configModel赋值,
从而改变子控制器定死,需要手动添加的问题:
@Override
public void init() throws ServletException {
//这里是请求的servlet,暂时定死,下篇文章进行优化。
//actions.put("/Book", new BookAction());
try {
configModel = ConfigModelFactory.bulid();
} catch (Exception e) {
e.printStackTrace();
}
}
2.3 拿到配置文件中的全路径名,反射实例化。
//相比于上一种从Map集合获取控制器,当前需要获取config.xml中的全路径名,然后反射实例化。
ActionModel actionModel = configModel.pop(uri);
if(actionModel == null) {
throw new RuntimeException("action 配置错误");
}
//Action子控制器的全路径名
String type = actionModel.getType();
try {
Action action = (Action) Class.forName(type).newInstance();
//调用处理请求的方法
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
2.4 测试运行
我们看到运行效果和上篇文章一样,代表第一个目标优化成功!
三、优化参数传递装代码
每当我们需要从前台传参数到后台接收,然后封装进一个实体类,
然后再把这个实体类塞进数据库中的时候,我们通常是这样做的:
//获取表单传过来的值
String bid = req.getParameter("bid");
String bname = req.getParameter("bname");
String price = req.getParameter("price");
//实例化对象
Book book = new Book(Integer.valueOf(bid), bname, Float.valueOf(price));
//调用数据访问层
BookDao bd = new BookDao();
//调用增加方法
bd.addBook(book);
对于单个表单个业务来说还好,但是一旦数据库表或者需求业务多起来就不得了。
代码及其繁多,并且重复代码量多。
所以我们想到怎么把那些重复要做的事情让别人提前封装好做好,我们就直接调用就好了:
开始我们的主题吧:
3.1 创建一个模型驱动接口:ModelDrivenpackage com.leaf.mvc; public interface ModelDriven{ //拿到将要封装的类实例 ModelDriven.getModel() 等价于---> new Book(); T getModel(); }
根据需求,我们在中央控制器正式调用处理请求的方法前就要给对应的实体类赋值:
3.2 获取相关实体类并且赋值所以,我们先判断一下拿到的子控制器是否实现接口:ModelDriven,
如果实现过接口,就让它向上转型为这个接口类,
然后调用这个接口的方法获取实例,
接着我们需要给获取到的这个实例赋值,利用req.getParameterMap。
代码如下:
try {
Action action = (Action) Class.forName(type).newInstance();
if(action instanceof ModelDriven) {//实现了接口
//转型
ModelDriven md = (ModelDriven) action;
//获取实例
Object model = md.getModel();
//要给model的属性赋值,就要接收前端Jsp参数
//将前端所有参数封装进实体类
BeanUtils.populate(model, req.getParameterMap());
}
//调用处理请求的方法之前就要给实体类赋值
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
3.3 继承接口类
我们让写方法的类继承这个接口:ModelDriven
然后把需要用到的实体类封装出来:
//封装一个Book实体类
private Book book = new Book();
继承一个接口必然要实现它的方法:getModel();
然后经过前面在中央控制器的赋值,这个时候就可以直接用了。
3.4 测试运行@Override
public Book getModel() {
return book;
}
优化MVC增删改查 增加 删除 修改 查询
private void add(HttpServletRequest req,HttpServletResponse resp) throws Exception {
//获取输出流out
PrintWriter out = resp.getWriter();
out.print("");
}
可以看到封装成功!
四、优化方法执行结果转发||重定向
当我们的要处理的业务不一样的时候,需要用到的页面跳转的方法也不一样,所以这里我们来优化一下相关的代码,让它合理的跳转页面而不写死。
4.1 改造子控制器把之前子控制器的方法返回值由无返回void改为String,然后再把与其相关的类的方法都改一下:
String execute(HttpServletRequest req,HttpServletResponse resp);
让处理业务的方法返回配置文件里的name值:
private String add(HttpServletRequest req,HttpServletResponse resp) throws Exception {
//获取输出流out
PrintWriter out = resp.getWriter();
out.print("");
return "failed";
}
配置文件中的两个name值对应着是用重定向还是转发,
所以我们再在总控制器通过业务方法返回name值--->获取是否重定向的配置--->然后再判断。
4.2 在总控制器判断是否重定向 String result = action.execute(req, resp);//获取到方法的返回值
ForwardModel forwardModel = actionModel.pop(result);
if(forwardModel == null) {
throw new RuntimeException("forward 配置错误");
} else {
//拿到是否重定向的配置
boolean redirect = forwardModel.isRedirect();
String path = forwardModel.getPath();
if(redirect)
//重定向
resp.sendRedirect(req.getContextPath()+path);
else {
//转发
req.getRequestDispatcher(path).forward(req, resp);
}
}
4.3 测试运行
我们可以看到我们写的判断成功~
五、实现框架配置文件可变
有的时候我们需要用到许多许多的框架,但是框架之间却有重名的可能,互相之间是会有影响的,所以我们还需要让这个配置文件的名字可变,且不影响项目运行。
5.1 配置web.xml文件首先我们需要把中央控制器的配置到web.xml里面:
mvc com.leaf.mvc.DispatcherServlet mvc *.action
这里注意:原来中央控制器配置的位置一定要注释掉,不然会相互冲突!
然后我们把框架的配置文件信息也配置进来:
5.2 获取配置文件名mvc com.leaf.mvc.DispatcherServlet configLocation /Leaf.xml
我们再回到中央控制器,这里我们可以用到方法:
this.getInitParameter("这里放的就是web.xml中配置的
这个方法可以获取到
//getInitParameter()的作用是拿到web.xml中的servlet信息配置的参数
String configLocation = this.getInitParameter("configLocation");
然后我们再判断configLocation是否为空,要是为空就调用默认的配置文件名。
完整代码:
@Override
public void init() throws ServletException {
//这里是请求的servlet,暂时定死,下篇文章进行优化。
//actions.put("/Book", new BookAction());
try {
//getInitParameter()的作用是拿到web.xml中的servlet信息配置的参数
String configLocation = this.getInitParameter("configLocation");
if(configLocation == null || "".equals(configLocation))
configModel = ConfigModelFactory.bulid();
else
configModel = ConfigModelFactory.bulid(configLocation);
} catch (Exception e) {
e.printStackTrace();
}
}
5.3 测试运行
我们发现就算把配置文件名改了也没有关系,不会影响项目运行。
OK,今天Leaf带来的学习笔记分享就到这里啦,喜欢的可以关注一起学习噢~有问题也读可以私信我或者评论!下次见啦!!!



