mvc框架upgrade

  • 针对上一篇文字做出了改造,既然要写手写lowb版mvc框架,就得付出一定代价,加大代码量,只考虑实现业务
    上一篇的升级版
  • 更改的地方:
    1. 使用xml配置文件代替config.properties,更灵活方便,用来映射请求方式与实现业务类的路径
    2. 按规则封装了request请求对象中的数据,规则(a. 表单中的表单元素名称同实体类中属性的名称一样 b. 表单中的元素名称 以 实体对象.属性名称命名)
    3. 一个服务类就可完成增删改查业务逻辑操作

1. actionservlet核心控制器更改以上1,2点

  • action.xml 映射请求路径和服务类全路径
  • 描述action.xml 的数据结构
package com.lovely.mvc;

/**
 * 
 * @author echo lovely
 * 
 * action.xml 映射数据, 加载xml中的类
 *
 */
public class MapperAction {
	
	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;
	}
	
	@Override
	public String toString() {
		return "MapperAction [path=" + path + ", type=" + type + "]";
	}
	
}

  • 核心控制器实现更改
package com.lovely.mvc;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.lovely.util.ConvertUtil;

public class ActionServlet extends HttpServlet {

	/**
	 * 核心控制servlet
	 * 根据访问方式 和 类的路径信息 到对应的servlet来处理
	 */
	private static final long serialVersionUID = 1L;
	
	Map<String, MapperAction> map = new HashMap<String, MapperAction>();
	
	@Override
	public void init() throws ServletException {
		// 加载xml内容 调用具体服务类
		SAXReader reader = new SAXReader();
		
		InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/action.xml");
		
		try {
			Document doc = reader.read(in);
			
			List<Element> list = doc.selectNodes("//action");
			
			for (Element action : list) {
				String path = action.elementText("path");
				String type = action.elementText("type");
				MapperAction mapper = new MapperAction();
				mapper.setPath(path);
				mapper.setType(type);
		
				map.put(path, mapper);
			}
			
		} catch (DocumentException e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null)
					in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String uri = req.getRequestURI();
		String key = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf("."));

		// 根据请求对象 拿到对应的类 进行服务
		String value = map.get(key).getType();
		
		if (value == null) {
			resp.sendError(404, key + "不在配置文件xml中");
			return;
		}
		
		try {
			// 反射拿到类对象
			Class<?> c = Class.forName(value);
			
			// 创建action对象
			Action action = (Action) c.newInstance();
			
			// 对request请求数据进行封装		
			// xxx服务类直接拿到 前台数据
			Map<String, String[]> requestMap = req.getParameterMap();
			Set<Entry<String,String[]>> entrySet = requestMap.entrySet();
			
			// 对表单提交过来的每个值 封装到xxxaction服务类中的属性
			for (Entry<String, String[]> entry : entrySet) {
				// 表单的名字
				String name = entry.getKey();
				// 表单的值 
				String[] formValue = entry.getValue();
				
				// 判断表单元素的名称是p.name 或者 是name 这里判断是 name
				if (name.indexOf(".") == -1) {
					// 直接提交属性名 为xxxAction中的属性赋值
					try {
						Field field = c.getDeclaredField(name);
						field.setAccessible(true);
						// 属性的类型可能是 String int/Integer double/Double boolean Date/Timstamp Integer[]/int[] Double[]/doble[] 转型
						field.set(action, ConvertUtil.convert(field, formValue));
					} catch (NoSuchFieldException e) {
						
						//e.printStackTrace(); 可能没这个属性
					} catch (SecurityException e) {
						e.printStackTrace();
					}
					
					
				} else {
					// 提交的值 封装到对象中
					try {
						// p.name p.age 表单元素的名称写法  对象.属性
						String[] split = name.split("\\.");
						// 父级对象属性
						Field fieldEntity = c.getDeclaredField(split[0]);
						fieldEntity.setAccessible(true);
						// 取到对象
						Object entity = fieldEntity.get(action);
						// 空对象
						if (entity == null) {
							// 拿到属性对象的类型 创建对象
							entity = fieldEntity.getType().newInstance();
							fieldEntity.set(action, entity);
						}		
						// 取到二级对象 
						// f.name 取到name			
						// 父级属性类对象
						Class<?> ff = fieldEntity.getType();
						Field field = ff.getDeclaredField(split[1]);
						field.setAccessible(true);
						
						// 设置 p.name 的值 转型
						field.set(entity, ConvertUtil.convert(field, formValue));
						
						
					} catch (NoSuchFieldException e) {
						// e.printStackTrace();
					} catch (SecurityException e) {
						e.printStackTrace();
					}
					
				}
				
			}
			
			String result = action.service(req, resp);
			
			if (result == "")
				return;
			
			if (result != null) {
				// 根据返回结果 决定是请求转发 还是重定向
				if (result.startsWith("forward")) {
					String path = result.split(":")[1];
					req.getRequestDispatcher(path).forward(req, resp);
				} else if (result.startsWith("redirect")) {
					String path = result.split(":")[1];
					resp.sendRedirect(req.getContextPath() + path);
				} else {
					// 写路径默认请求转发
					req.getRequestDispatcher(result).forward(req, resp);
				}				
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

}

2. 工具类(对反射拿到的属性对象数据转型)

  • 由于数据库dao层使用ConverUtil中的convert, 所以为了不改代码,使用重载设计
package com.lovely.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

public class ConvertUtil {
	
	/**
	 * 把数据库查出来的string转换为对应的属性类型
	 * @param f 属性对象
	 * @param value rs结果集中返回的string值
	 * @return 返回属性对象的值
	 */
	public static Object convert(Field f, String value) {
		
		if (value == null)
			return null;
		
		Object obj = null;
		
		try {
			if (f.getType() == Date.class) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
				java.util.Date date = sdf.parse(value);			
				// 把util日期转换成 sql 日期
				obj = new Date(date.getTime());
				
			} else if (f.getType() == Timestamp.class) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				java.util.Date date = sdf.parse(value);
				obj = new Timestamp(date.getTime());
			} else {
				// 属性对象 是Double Integer 之类的转型
				Class<?> type = f.getType();
				
				// getClass 得到本身类名路径 getType得到当前类型
				// System.out.println(type + "\t" + f.getClass() + "\t" + (type == f.getClass()));
				
				Constructor<?> con = type.getDeclaredConstructor(String.class);
				
				obj = con.newInstance(value);
				
			}			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return obj;
	}
	
	/**
	 * 封装的属性对象值可能是 各种类型滴 考虑转型...
	 * @param f 要被赋值的属性对象
	 * @param value 被转换的值
	 * @return 转换属性对象对应类型的值
	 */
	public static Object convert(Field f, String[] value) {
		
		if (value == null || value.length == 0)
			return null;
		
		Object obj = null;
		
		try {
			if (f.getType() == Date.class) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
				java.util.Date date = sdf.parse(value[0]);			
				// 把util日期转换成 sql 日期
				obj = new Date(date.getTime());
				
			} else if (f.getType() == Timestamp.class) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				java.util.Date date = sdf.parse(value[0]);
				obj = new Timestamp(date.getTime());
			} else if ((f.getType() == int.class || f.getType() == Integer.class) && value[0] != "") { // 判断提交的数不是空字符
				obj = new Integer(value[0]);
			} else if ((f.getType() == double.class || f.getType() == Double.class) && value[0] != "") {
				obj = new Double(value[0]);
			} else if (f.getType() == String.class && value[0] != "") {
				obj = value[0];
			} else if (f.getType() == Integer[].class) {
				Integer[] integer = new Integer[value.length];
				for (int i = 0; i < value.length; i++) {
					integer[i] = new Integer(value[i]);
				}
				obj = integer;
			} else if (f.getType() == int[].class) {
				int[] arr = new int[value.length];
				for (int i = 0; i < arr.length; i++) {
					arr[i] = Integer.parseInt(value[i]);
				}
			} else if ((f.getType() == boolean.class || f.getType() == Boolean.class) && value[0] != "") {
				if (value[0] == "y" || value[0] == "1" || value[0] == "true") {
					obj = true;
				} else {
					obj = false;
				}		
			}
				
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return obj;
	}

}

3. 业务服务类使用适配器设计模式

  • 表现层接口
package com.lovely.mvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface Action {
	
	// service服务方法接口
	public String service(HttpServletRequest req, HttpServletResponse resp);

}

  • 适配器实现接口
package com.lovely.mvc;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// 实体服务类规范
public class DispatcherAction implements Action {

	public String service(HttpServletRequest req, HttpServletResponse resp) {
	
		// 反射执行子类方法
		Class<?> c = this.getClass();
		// 请求方法
		String method = req.getParameter("method");
		
		String returnValue = "";
		try {
			// 反射拿到子类的方法对象
			Method methodObj = c.getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);
			
			// 调用具体的方法
			returnValue = methodObj.invoke(this, req, resp).toString();		
			
		} catch (NoSuchMethodException e) {
			try {
				resp.sendError(404, method + "方法不存在...");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}		
		
		return returnValue;
	}

}

  • 作为使用者,使用服务类完成业务
package com.lovely.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.lovely.dao.CommonDao;
import com.lovely.entity.Ticket;
import com.lovely.mvc.DispatcherAction;

public class TicketAction extends DispatcherAction {
	
	CommonDao dao = new CommonDao();
	
	// 查询
	public String queryAll(HttpServletRequest req, HttpServletResponse resp) {
		
		req.setAttribute("list", dao.queryAll(Ticket.class));
		
		return "/index.jsp";
	}

	// 会被核心控制器封装数据的 对象
	private Ticket t;
	
	// 新增票
	public String save(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println(t);
		int count = dao.save(t);
		if (count > 0)
				return "/TicketAction.do?method=queryAll";
			
		return "/add.jsp";
	}
	
	// 根据id查询票
	public String findOneTicket(HttpServletRequest req, HttpServletResponse resp) {
		req.setAttribute("ticket", dao.queryOne(t));
		return "/update.jsp";
	}
	
	// 修改票
	public String update(HttpServletRequest req, HttpServletResponse resp) {
		int count = dao.update(t);
		
		if (count > 0)
			return "redirect:/TicketAction.do?method=queryAll";
		
		return "/TicketAction.do?method=findOneTicket";
	}
	
	// 删除票
	public String delete(HttpServletRequest req, HttpServletResponse resp) {
		int count = dao.delete(t);
		
		if (count > 0)
			return "/TicketAction.do?method=queryAll";
		else 
			return "/TicketAction.do?method=queryAll";
	}
	
}

猜你喜欢

转载自blog.csdn.net/qq_44783283/article/details/107168091
今日推荐