当前位置:网站首页>自定义mvc框架实现
自定义mvc框架实现
2022-06-29 08:51:00 【lion tow】
目录
一、中央控制器动态加载存储子控制器
上次分享到,我们如何优化不同的对象在想要实现不同功能时为了方便编码进行的创建了MVC框架进行优化,但是还是不够方便所以我们继续优化一下:
问题一:中央控制器每次初始化都要手动添加初始化

分析解决:
1.通过XML建模我们可以知道,最终configModel对象会包含config.xml中所有子控制器的信息
2.同时为了解决中央控制器能够动态加载保存子控制器的信息,那么我们只需要引入congigModel对象一样也可以初始化
所以我们需要运用我们XML建模的知识:
config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/book" type="com.zq.Servlet.BookAction">
<forward name="failed" path="/login.jsp" redirect="false" />
<forward name="success" path="/main.jsp" redirect="true" />
</action>
</config>对DispatcherServlet进行改造:
package com.zq.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;
/**
* 中央控制器
* 主要职能:接受浏览器请求 ,找到对应的处理人
* @author 张强
*
* 2022年6月25日下午2:32:46
*/
@WebServlet("*.action")
public class DispatcherServlet extends HttpServlet{
private Map<String, Action> actions = new HashMap<String, Action>();
//通过建模我们可以知道最终ConfigModel对象会包含config.xml中的所有自控制信息
private ConfigModel ConfigModel;
//程序启动的时候就会执行一次
@Override
public void init() throws ServletException {
// actions.put("/book", new BookAction());
// actions.put("/order", new OrederAction());
try {
ConfigModel= ConfigModelFactory.bulid();
} catch (Exception e) {
// TODO Auto-generated catch block
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 {
String uri = req.getRequestURI();
//要拿到/book
uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
//Action action = actions.gaet(uri);
//相比于上一种从map集合中获取子控制器,当前需要获取config.xml中的全路径名,然后反射实例化
ActionModel actionModel = ConfigModel.pop(uri);
if(actionModel == null) {
throw new RuntimeException("action 配置 错误");
}
String type = actionModel.getType();//配置文件中的全路径名 action子控制器的全路径名
try {
Action action = (Action) Class.forName(type).newInstance();//action的实例
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
页面代码:Demo01:
<h2>优化</h2>
<a href="${pageContext.request.contextPath}/book.action?methodName=add">增加</a>
<a href="${pageContext.request.contextPath}/book.action?methodName=del">删除</a>
<a href="${pageContext.request.contextPath}/book.action?methodName=update">修改</a>
<a href="${pageContext.request.contextPath}/book.action?methodName=check">查看</a>
<a href="${pageContext.request.contextPath}/book.action?methodName=load">回显</a>
做到这里我们就可以实现不需要改动任何代码只用修改XML配置文件就可以添加子控制器了
二、参数传递封装的优化
问题二:我们传递参数过多能不能不需要我用req.getp直接可以拿到传递的参数?
Demo1:我们以add为例子我们传递了三个参数bid、bname、price
<h2>参数传递优化</h2>
<a href="${pageContext.request.contextPath }/book.action?methodName=add&bid=989898&bname=laoliu&price=89">增加</a>
<a href="${pageContext.request.contextPath}/book.action?methodName=del">删除</a>
<a href="${pageContext.request.contextPath}/book.action?methodName=update">修改</a>
<a href="${pageContext.request.contextPath}/book.action?methodName=check">查看</a>
<a href="${pageContext.request.contextPath}/book.action?methodName=load">回显</a>建一个com.zq.entity的包 在其内建一个Book的实体类
package com.zq.entity;
public class book {
private int bid;
private String bname;
private float price;
public int getBid() {
return bid;
}
public void setBid(int bid) {
this.bid = bid;
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
return "Book [bid=" + bid + ", bname=" + bname + ", price=" + price + "]";
}
}
优化前的add方法:
package com.zq.Servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zq.entity.book;
import com.zq.framework.Action;
import com.zq.framework.ActionSupport;
public class BookAction extends ActionSupport {
private void load(HttpServletRequest request, HttpServletResponse response) {
System.out.println("在同一个Servlet中,调用查询单个的方法");
}
private void check(HttpServletRequest request, HttpServletResponse response) {
System.out.println("在同一个Servlet中,调用查看的方法");
}
private void update(HttpServletRequest request, HttpServletResponse response) {
System.out.println("在同一个Servlet中,调用修改的方法");
}
private void del(HttpServletRequest request, HttpServletResponse response) {
System.out.println("在同一个Servlet中,调用删除的方法");
}
private void add(HttpServletRequest request, HttpServletResponse response) {
String bid = request.getParameter("bid");
String bname = request.getParameter("bname");
String price = request.getParameter("price");
book book = new book();
book.setBid(Integer.valueOf(bid));
book.setBname(bname);
book.setPrice(Float.valueOf(price));
System.out.println("在用一个servlet中调用 add 方法"+book);
}
}
我们如果传值很多的话就需要接受非常多的重复的代码所以就优化他:
优化BookAction:
package com.zq.Servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zq.entity.book;
import com.zq.framework.Action;
import com.zq.framework.ActionSupport;
import com.zq.framework.ModelDriven;
public class BookAction extends ActionSupport implements ModelDriven<book>{
private book book = new book();
private void list(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("在用一个servlet中调用 list 方法");
}
private void load(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));
System.out.println("在用一个servlet中调用 add 方法"+book);
}
@Override
public book getModel() {
return book;
}
}
创建一个接口ModelDriven:
package com.zq.entity;
public class book {
private int bid;
private String bname;
private float price;
public int getBid() {
return bid;
}
public void setBid(int bid) {
this.bid = bid;
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
return "Book [bid=" + bid + ", bname=" + bname + ", price=" + price + "]";
}
}
改造 DispatcherServlet:
package com.zq.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 org.apache.commons.beanutils.BeanUtils;
/**
* 中央控制器
* 主要职能:接受浏览器请求 ,找到对应的处理人
* @author 张强
*
* 2022年6月25日下午2:32:46
*/
@WebServlet("*.action")
public class DispatcherServlet extends HttpServlet{
private Map<String, Action> actions = new HashMap<String, Action>();
//通过建模我们可以知道最终ConfigModel对象会包含config.xml中的所有自控制信息
private ConfigModel ConfigModel;
//程序启动的时候就会执行一次
@Override
public void init() throws ServletException {
// actions.put("/book", new BookAction());
// actions.put("/order", new OrederAction());
try {
ConfigModel= ConfigModelFactory.bulid();
} catch (Exception e) {
// TODO Auto-generated catch block
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 {
String uri = req.getRequestURI();
//要拿到/book
uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
//Action action = actions.gaet(uri);
//相比于上一种从map集合中获取子控制器,当前需要获取config.xml中的全路径名,然后反射实例化
ActionModel actionModel = ConfigModel.pop(uri);
if(actionModel == null) {
throw new RuntimeException("action 配置 错误");
}
String type = actionModel.getType();//配置文件中的全路径名 action子控制器的全路径名
try {
Action action = (Action) Class.forName(type).newInstance();//action的实例
if(action instanceof ModelDriven) {
//所以可以将其进行向下转型
ModelDriven md = (ModelDriven)action;
//model指的是bookAction中的book类实例
Object model = md.getModel();
//给model中的属性赋值,要接受前端jsp传递的参数 req.getParameterMap()
//PropertyUtils.getIndexedProperty(bean, name) 从某个对象中取某个值
//将前端所有参数值封装进实体类
BeanUtils.populate(model, req.getParameterMap());
}
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、返回值页面跳转优化
问题三:我们在实现功能后会有页面跳转的需求但是能不能不要添加重复的代码但是能够实现跳转功能呢?
解决方法是将我们的跳转路径也一样的放置在XML配置文件中
对子控制器进行改造:
package com.zq.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 子控制器
* 对应的处理人
* @author 张强
*
* 2022年6月25日下午2:34:21
*/
public interface Action {
String execute(HttpServletRequest request, HttpServletResponse response);
}
ForwardModel:
package com.zq.framework;
/**
* 对应forward标签
* @author yang
*
* @date 2022年6月15日上午9:05:38
*/
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 getRedirect() {
return redirect;
}
public void setRedirect(boolean b) {
this.redirect = b;
}
public boolean isRedirect() {
return redirect;
}
}
ActionSupport:
package com.zq.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 request, HttpServletResponse response) {
String methodName = request.getParameter("methodName");
// methodName可能是add/del/edit/list/load/xxx/yyy/aaa...
// 前台传递什么方法,就调用当前类的对应方法
try {
Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
m.setAccessible(true);
// 调用当前类实例的methodName方法
return (String) m.invoke(this, request,response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
DispatcherServlet:
package com.zq.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 org.apache.commons.beanutils.BeanUtils;
/**
* 中央控制器
* 主要职能:接受浏览器请求 ,找到对应的处理人
* @author 张强
*
* 2022年6月25日下午2:32:46
*/
@WebServlet("*.action")
public class DispatcherServlet extends HttpServlet{
private Map<String, Action> actions = new HashMap<String, Action>();
//通过建模我们可以知道最终ConfigModel对象会包含config.xml中的所有自控制信息
private ConfigModel ConfigModel;
//程序启动的时候就会执行一次
@Override
public void init() throws ServletException {
// actions.put("/book", new BookAction());
// actions.put("/order", new OrederAction());
try {
ConfigModel= ConfigModelFactory.bulid();
} catch (Exception e) {
// TODO Auto-generated catch block
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 {
String uri = req.getRequestURI();
//要拿到/book
uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
//Action action = actions.gaet(uri);
//相比于上一种从map集合中获取子控制器,当前需要获取config.xml中的全路径名,然后反射实例化
ActionModel actionModel = ConfigModel.pop(uri);
if(actionModel == null) {
throw new RuntimeException("action 配置 错误");
}
String type = actionModel.getType();//配置文件中的全路径名 action子控制器的全路径名
try {
Action action = (Action) Class.forName(type).newInstance();//action的实例
if(action instanceof ModelDriven) {
//所以可以将其进行向下转型
ModelDriven md = (ModelDriven)action;
//model指的是bookAction中的book类实例
Object model = md.getModel();
//给model中的属性赋值,要接受前端jsp传递的参数 req.getParameterMap()
//PropertyUtils.getIndexedProperty(bean, name) 从某个对象中取某个值
//将前端所有参数值封装进实体类
BeanUtils.populate(model, req.getParameterMap());
// 正式调用此方法之前 book中的属性要被赋值
String result = action.execute(req,resp);
ForwardModel forwardModel = actionModel.pop(result);
// if(forwardModel == null)
// throw new RuntimeException("forward config error");
// /bookList.jsp /index.jsp
String path = forwardModel.getPath();
//拿到是否需要转发的配置
boolean redirect = forwardModel.isRedirect();
if(redirect)
resp.sendRedirect(path);
else
req.getRequestDispatcher(path).forward(req, resp);
}
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
但是如果我们现在进行测试看能否跳转界面的话应该会出现路径丢失了项目名的情况

解决的方法就是再次修改 DispatcherServlet:
//拿到是否需要转发的配置
boolean redirect = forwardModel.isRedirect();
if(redirect)
resp.sendRedirect(req.getServletContext().getContextPath()+path);
else
req.getRequestDispatcher(path).forward(req, resp);
四、框架配置文件可变
问题四:如果我们更改了XML配置文件的文件名又该怎么办呢?
修改一下 DispatcherServlet:
package com.zq.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 org.apache.commons.beanutils.BeanUtils;
/**
* 中央控制器
* 主要职能:接受浏览器请求 ,找到对应的处理人
* @author 张强
*
* 2022年6月25日下午2:32:46
*/
@WebServlet("*.action")
public class DispatcherServlet extends HttpServlet{
private Map<String, Action> actions = new HashMap<String, Action>();
//通过建模我们可以知道最终ConfigModel对象会包含config.xml中的所有自控制信息
private ConfigModel ConfigModel;
//程序启动的时候就会执行一次
@Override
public void init() throws ServletException {
// actions.put("/book", new BookAction());
// actions.put("/order", new OrederAction());
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) {
// TODO Auto-generated catch block
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 {
String uri = req.getRequestURI();
//要拿到/book
uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
//Action action = actions.gaet(uri);
//相比于上一种从map集合中获取子控制器,当前需要获取config.xml中的全路径名,然后反射实例化
ActionModel actionModel = ConfigModel.pop(uri);
if(actionModel == null) {
throw new RuntimeException("action 配置 错误");
}
String type = actionModel.getType();//配置文件中的全路径名 action子控制器的全路径名
try {
Action action = (Action) Class.forName(type).newInstance();//action的实例
if(action instanceof ModelDriven) {
//所以可以将其进行向下转型
ModelDriven md = (ModelDriven)action;
//model指的是bookAction中的book类实例
Object model = md.getModel();
//给model中的属性赋值,要接受前端jsp传递的参数 req.getParameterMap()
//PropertyUtils.getIndexedProperty(bean, name) 从某个对象中取某个值
//将前端所有参数值封装进实体类
BeanUtils.populate(model, req.getParameterMap());
// 正式调用此方法之前 book中的属性要被赋值
String result = action.execute(req,resp);
ForwardModel forwardModel = actionModel.pop(result);
// if(forwardModel == null)
// throw new RuntimeException("forward config error");
// /bookList.jsp /index.jsp
String path = forwardModel.getPath();
//拿到是否需要转发的配置
boolean redirect = forwardModel.isRedirect();
if(redirect)
resp.sendRedirect(path);
else
req.getRequestDispatcher(path).forward(req, resp);
}
action.execute(req, resp);
} 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.cdl.framework.DispatcherServlet</servlet-class>
<init-param>
<param-name>configLaction</param-name>
<param-value>/wuyanzu2</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>将config.xml->wuyanzu2.xml
这样的话就算是我们自己修改配置文件的名字也不会出现任何的问题啦
边栏推荐
- A 3D Dual Path U-Net of Cancer Segmentation Based on MRI
- In the era of data processing, data quality construction is the way for enterprises to survive
- es报错NoNodeAvailableException[None of the configured nodes are available:[.127.0.0.1}{127.0.0.1:9300]
- Simplicity studio does not recognize the new JLINK V9 solution
- pytorch总结学习系列-操作
- General part: cognition, design and best practice of prototype design
- How to do unit test well
- Go deep into RC, RS, daemonset and statefulset (VII)
- Closed door cultivation (24) shallow understanding of cross domain problems
- Deep Learning-based Automated Delineation of Head and Neck Malignant Lesions from PET Images
猜你喜欢

LSM6DSL之SPI驱动

转载 :判断对象是否具有属性的5种方法

Written test question "arrange version numbers from large to small"

UE4 display 3D editable points in Viewport

1.4 regression of machine learning methods

【华为认证】HCIA-DATACOM史上最全精选题库(附答案解析)

Wechat applet user refuses to authorize geographic location information and calls up the authorization window again

Simplicity Studio无法识别新买的JLink v9解决方法

MATLAB小技巧(21)矩阵分析--偏最小二乘回归

KiCad学习笔记--快捷键
随机推荐
Automatic 3D Detection and Segmentation of Head and Neck Cancer from MRI Data.
Wechat applet opens file stream
Basic operations of MAC MySQL database
Mysql配置主从数据库
Lc236. nearest common ancestor of binary tree
UE4 VS的Visual Assist插件设置
Write down some written test questions
商业智能BI的未来,如何看待AI+BI这种模式?
InvalidConnectionAttributeException异常处理
Redo after JS rotation view (longer full version, can be run)
[technology development] development and design of alcohol tester solution
Automatic Multi-Organ SegmVentation on Abdominal CT With Dense V-Networks
Written test question "arrange version numbers from large to small"
Universal target detection based on region attention
Mongodb persistence
# 《网络是怎么样连接的》读书笔记 - WEB服务端请求和响应(四)
MATLAB小技巧(21)矩阵分析--偏最小二乘回归
你必须知道的23个最有用的Elasticseaerch检索技巧
Mh/t 6040 smoke density test of aviation materials
Print service IP setting scheme
