当前位置:网站首页>自定义MVC 2.0
自定义MVC 2.0
2022-07-24 05:18:00 【zsm030616】
一、让中央控制器动态加载存储子控制器
在定义MVC工作原理中,中央控制器起到了接收浏览器请求,找到对应的处理人的一个作用,但同时也存在缺陷,例如:就像在每一次访问前台时,有很多个部门,每访问一次,就要new一个此类。
所以为了提高代码的效率,通过xml建模,到config文件中进行操作。
第一步对中央控制器进一步做出优化改进:
1、通过url来找到config文件中对应的action对象
2、然后通过该对象来取到路径名servlet.BookAction
3、然后找到对应的方法执行
DispatcherServlet:
package com.zsm.framework;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zsm.web.BookAction;
/**
* 中央控制器:
* 主要职能:接收浏览器请求,找到对应的处理人
* @author zjjt
*
*/
@WebServlet("*.action")
public class DispatcherServlet extends HttpServlet{
/**
* 通过建模我们可以知道,最终ConfigModel对象会包含config.xml中的所有子控制器信息
* 同时为了解决中央控制器能够动态加载保存子控制器的信息,那么我们只需要引入configModel对象即可
*/
private ConfigModel configModel;
// 程序启动时,只会加载一次
@Override
public void init() throws ServletException {
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 {
//http:localhost:8080/mvc/book.action?methodName=list
String uri=req.getRequestURI();
// 拿到/book,就是最后一个“/”到最后一个“.”为止
uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
// 相比于上一种从map集合获取子控制器,当前需要获取config.xml中的全路径名,然后反射实例化
ActionModel actionModel = configModel.pop(uri);
if(actionModel==null) {
throw new RuntimeException("action 配置错误");
}
String type = actionModel.getType();
// type是Action子控制器的全路径名
try {
Action action= (Action) Class.forName(type).newInstance();
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
二、参数传递封装优化
由于做项目过程中,在servlet类中需要接受很多个参数值,比如:一个实体类Book当中有十个属性,那么你在进行修改时就要接受十个值,虽然每次接受语句中的属性值不一样,但从根本上来讲,性质是一样,要接收属性。
为了解决这个问题
我们建一个模型驱动接口,使BookAction实现该接口,在中央控制器中将所有要接收的参数封装到模型接口中,从而达到简便的效果。
ModelDriven类(驱动接口类):
package com.zsm.framework;
/**
* 模型驱动接口,接收前台JSP传递的参数,并且封装到实体类中
* @author zjjt
*
* @param <T>
*/
public interface ModelDriven<T> {
// 拿到将要封装的类实例 ModelDriven.getModel() ---> new Book();
T getModel();
}
DispatcherServlet 中央控制器类:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//http:localhost:8080/mvc/book.action?methodName=list
String uri=req.getRequestURI();
// 拿到/book,就是最后一个“/”到最后一个“.”为止
uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
// Action action = actions.get(uri);
// 相比于上一种从map集合获取子控制器,当前需要获取config.xml中的全路径名,然后反射实例化
ActionModel actionModel = configModel.pop(uri);
if(actionModel==null) {
throw new RuntimeException("action 配置错误");
}
String type = actionModel.getType();
// type是Action子控制器的全路径名
try {
Action action= (Action) Class.forName(type).newInstance();
// action是bookAction
if(action instanceof ModelDriven) {
ModelDriven md=(ModelDriven) action;
// model指的是bookAction中的book实例
Object model = md.getModel();
// 要给model中的属性赋值,要接收前端jsp参数 req.getParameterMap()
// PropertyUtils.getProperty(bean, name)
// 将前端所有的参数值封装进实体类
BeanUtils.populate(model, req.getParameterMap());
System.out.println(model);
}
// 正式调用方法前,book中的属性要被赋值
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
BookAction类:
package com.zsm.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zsm.entity.Book;
import com.zsm.framework.Action;
import com.zsm.framework.ActionSupport;
import com.zsm.framework.ModelDriven;
public class BookAction extends ActionSupport implements ModelDriven<Book>{
private Book book=new Book();
private void load(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("在同一个servlet中调用 load 方法");
}
private void list(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("在同一个servlet中调用 list 方法");
}
private void edit(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("在同一个servlet中调用 edit 方法");
}
private void del(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("在同一个servlet中调用 del 方法");
}
private void add(HttpServletRequest req, HttpServletResponse resp) {
// String bid=req.getParameter("bid");
// String bname=req.getParameter("bname");
// String price=req.getParameter("price");
Book book=new Book();
// book.setBid(Integer.valueOf(bid));
// book.setBname(bname);
// book.setPrice(Float.valueOf(price));
// bookDao.add(book);
System.out.println("在同一个servlet中调用 add 方法");
}
@Override
public Book getModel() {
return null;
}
}
注意:在上一张同一个类里,没有实现ModelDriver接口,而如下bookaction类实现了ModelDriver接口,把接受多个参数的属性值语句注释,达到了简便的效果
其中关于解决参数冗余问题关键代码是:
BeanUtils.populate(bean, req.getParameterMap());
//将该对象要接受的参数值封装到对应的对象中
三、对于方法执行结果转发重定向优化
在我们跳转到另一个界面时,需要许很多关于跳转方式的代码,这些代码往往要写很多次,因此通过配置config文件来解决此类问题;
config.xml :
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/book" type="com.zsm.web.BookAction">
<forward name="success" path="/demo2.jsp" redirect="false" />
<forward name="failed" path="/demo3.jsp" redirect="true" />
</action>
</config>
解决问题思路
1、当点击增加或者编辑时,首先跳转的是中央控制器类(DispatchServlet):获取到url,url将决定要跳到哪一个实体类,
2、之后进入ActionSupport(子控制器接口实现类)通过methodname要调用什么方法,
3、再然后进入到BookAction中调用methodname方法,找到对应的返回值,
4、通过返回值在进入到config文件找到path属性,之后在中央控制器中进行判断,来决定是重定向还是转发。
中央控制器(DispatcherServlet):
String result = action.execute(req, resp);
ForwardModel forwardModel = actionModel.pop(result);
// if(forwardModel==null)
// throw new RuntimeException("forward config error");
String path = forwardModel.getPath();
// 拿到是否需要转发的配置
boolean redirect = forwardModel.isRedirect();
if(redirect)
//${pageContext.request.contextPath}
resp.sendRedirect(req.getServletContext().getContextPath()+path);
else
req.getRequestDispatcher(path).forward(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
ActionSupport(子控制器接口实现类):
package com.zsm.framework;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ActionSupport implements Action{
@Override
public String execute(HttpServletRequest req, HttpServletResponse resp) {
String methodName = req.getParameter("methodName");
// methodName可能是多种方法
// 前台传递什么方法就调用当前类的对应方法
try {
Method m=this.getClass()// BookServlet.Class
.getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
m.setAccessible(true);
// 调用当前类实例的 methodName 方法
return (String) m.invoke(this, req,resp);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
BookAction(图中标记的为返回值):

dome2
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
转发页面
</body>
</html>
dome3
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
重定向
</body>
</html>
四、框架配置可变
如果将配置文件的文件名进行改变,那么程序将无法运行。
因为 ConfigModelFactory 类里就定义了它的默认路径名如下:
为了在配置文件的文件名改变后依然能运行程序
我们可以在DispatcherServlet类里的init初始化里设置它的配置地址
@Override
public void init() throws ServletException {
// actions.put("/book", new BookAction());
// actions.put("/order", new BookAction());
try {
//配置地址
// getInitParameter的作用是拿到web.xml中的servlet信息配置的参数
String configLocation = this.getInitParameter("configLocation");
if(configLocation==null||"".equals(configLocation))
configModel=ConfigModelFactory.build();
else
configModel=ConfigModelFactory.build(configLocation);
} catch (Exception e) {
e.printStackTrace();
}
}
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>T280_mvc</display-name>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>com.zsm.framework.DispatcherServlet</servlet-class>
<init-param>
<param-name>configLocation</param-name>
<param-value>/zsm.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
如此,即便改变了配置文件的文件名,依然不影响程序的运行
边栏推荐
- AttributeError: ‘NoneType‘ object has no attribute ‘shape‘
- 利用二分法从数组中寻找具体数值
- Scope and scope chain
- Scikit learn notes
- day(0~6)代表每月第一天起始位置,stop代表每月天数,每天之间空两个空格。输入不同的day和stop,输出每月日历的样子。假设day为2,stop为31,则输出样式为
- 项目免费部署到公网(内网穿透)
- 关键字_02break与continue
- 一步一步带你学C(其一)
- Promise续(尝试自己实现一个promise)更详细的注释和其它接口暂未完成,下次咱们继续。
- C#进程运行权限
猜你喜欢

canvas - 填充

模板数据的二次加工

Pure white tutorial using Druid database connection pool in idea

Ain 0722 sign in

LaTeX学习笔记(一)——安装配置

A collation of the basic usage of numpy

赶紧进来!!带你了解什么是多文件,并轻松掌握 extern和static c语言关键字的用法!!!

赶紧进来!!轻松掌握C语言“顺序”、“分支”、“循环”三大结构

Implementation and comparison of nine sorting (ten thousand words summary)

一步一步带你学C(其二)
随机推荐
7. 在屏幕上绘制一条贝塞尔曲线,并用反走样技术对曲线进行平滑处理。
LaTeX学习笔记(一)——安装配置
Implementation and comparison of nine sorting (ten thousand words summary)
牛客网刷题
What is the function of key
[[[recursion]]]
赶紧进来!!带你了解什么是多文件,并轻松掌握 extern和static c语言关键字的用法!!!
C语言从入门到入土——函数
libc.so.6/glibc交叉编译
Install pytoch+anaconda+cuda+cudnn
Collation of commonly used Anaconda commands
C语言入门篇 二.函数
在屏幕上绘制一个正方形,用ice.bmp对正方形做纹理映射;在正方形后绘制一个黄色的茶壶,假设正方形是透明的,绘制茶壶与正方形的混合效果;通过A,D,W和K按键调整茶壶在X轴和Y轴的位置,具体如下
你真的知道判断语句吗?
special effects - 鼠标移动,出现自定义的表情拖尾
关键字_01return
Constructor_ Date constructor
C#进程运行权限
收藏==学废
Some experience of using D2L package and related environment configuration