Java web 中央控制器
Java web 中央控制器
mvc-servlet优化
beanMap相当于一个容器
http://localhost:8080/pro15/fruit.do?operate=edit&fid=2
在上面的链接中使用fruit.do找到Controller控制器.然后再通过
operate找到edit方法
抽取返回结果到中心控制器
在原本的方法之中我们发现在FruitController的各种方法比如update(),edit(),del(),add(),index()方法里面都有一个 response.sendRedirect("fruit.do");
重定向方法或者super.processTemplate("edit",request,response);
获取视图模板技术.所以我们打算将这两个方法抽离到DispatcherServlet当中去让中央控制器来实现跳转与实现.
这一节主要的优化就是将上面的两个方法抽离到中央控制器当中去
- 因为是中央控制器来调用这些方法所以我们可以将一个String返回给中央控制器.让中央控制器来接收.比如我们在update方法中返回redirect:fruit.do
private String update(HttpServletRequest request) throws ServletException {
//2.获取参数
String fidStr = request.getParameter("fid");
Integer fid = Integer.parseInt(fidStr);
String fname = request.getParameter("fname");
String priceStr = request.getParameter("price");
int price = Integer.parseInt(priceStr);
String fcountStr = request.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = request.getParameter("remark");
//3.执行更新
fruitDAO.updateFruit(new Fruit(fid, fname, price, fcount, remark));
// response.sendRedirect("fruit.do");
return "redirect:fruit.do";//只负责返回这个字符串
}
- 我们在edit()方法之中返回了edit
private String edit(HttpServletRequest request) throws IOException, ServletException {
String fidStr = request.getParameter("fid");
if (StringUtil.isNotEmpty(fidStr)) {
int fid = Integer.parseInt(fidStr);
Fruit fruit = fruitDAO.getFruitByFid(fid);
request.setAttribute("fruit", fruit);
// super.processTemplate("edit", request, response);
return "edit";
}
return "error";
}
这样我们就将字符串返回给了中央控制器.同时如果我们都这样处理的话,这些类中的HttpServletResponse response,以及很多异常就不在需要了.所以是可以进行删除的
-
让我们继续回到中央控制器,来进行进一步的抽取工作.我们在service()方法中找到了通过反射调用的方法.首先对代码
Object returnObj = method.invoke(controllerBeanObj, request);
的返回值接受为一个object对象,然后将这个对象强制转换为String类型. -
然后开始进行处理,首先判断该字符串是不是以redirect:为开头,如果是以redirect:为开头的话,这种情况就是要求重定向的方法,就截取redirect:后面的部分,然后通过
response.sendRedirect(redirectStr);
来调用截取的字符串. -
如果该字符串不是以redirect:为开头的话那么就要求调用视图模板技术,我们让DispatcherServlet 继承 ViewBaseServlet这样的话就可以直接通过
uper.processTemplate(methodReturnStr, request, response);
直接调用方法@WebServlet("*.do") public class DispatcherServlet extends ViewBaseServlet { private Map<String, Object> beanMap = new HashMap<>(); public DispatcherServlet() { } public void init() throws ServletException { super.init(); try { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml"); //1.创建DocumentBuilderFactory DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); //2.创建DocumentBuilder对象 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); //3.创建Document对象 Document document = documentBuilder.parse(inputStream); //4.获取所有的bean节点 NodeList beanNodeList = document.getElementsByTagName("bean"); for (int i = 0; i < beanNodeList.getLength(); i++) { Node beanNode = beanNodeList.item(i); if (beanNode.getNodeType() == Node.ELEMENT_NODE) { Element beanElement = (Element) beanNode; String beanId = beanElement.getAttribute("id"); String className = beanElement.getAttribute("class"); Class controllerBeanClass = Class.forName(className); Object beanObj = controllerBeanClass.newInstance(); beanMap.put(beanId, beanObj); } } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //设置编码 request.setCharacterEncoding("UTF-8"); //假设url是: http://localhost:8080/pro15/hello.do //那么servletPath是: /hello.do // 我的思路是: // 第1步: /hello.do -> hello 或者 /fruit.do -> fruit // 第2步: hello -> HelloController 或者 fruit -> FruitController String servletPath = request.getServletPath(); servletPath = servletPath.substring(1); int lastDotIndex = servletPath.lastIndexOf(".do"); servletPath = servletPath.substring(0, lastDotIndex); Object controllerBeanObj = beanMap.get(servletPath); String operate = request.getParameter("operate"); if (StringUtil.isEmpty(operate)) { operate = "index"; } try { Method method = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class); if (method != null) { //2.controller组件中的方法调用 method.setAccessible(true); Object returnObj = method.invoke(controllerBeanObj, request); //3.视图处理 String methodReturnStr = (String) returnObj; if (methodReturnStr.startsWith("redirect:")) { String redirectStr = methodReturnStr.substring("redirect".length());//获取redirect后面的内容 response.sendRedirect(redirectStr); } else { //这种情况返回的就是edit super.processTemplate(methodReturnStr, request, response); } } else { throw new RuntimeException("operate值非法!"); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
抽取获取参数到中心控制器
-
现在我们将获取参数的方式放到中央控制器当中去
这是我们原本的update()代码
private String update(HttpServletRequest request) throws ServletException { //2.获取参数 String fidStr = request.getParameter("fid"); Integer fid = Integer.parseInt(fidStr); String fname = request.getParameter("fname"); String priceStr = request.getParameter("price"); int price = Integer.parseInt(priceStr); String fcountStr = request.getParameter("fcount"); Integer fcount = Integer.parseInt(fcountStr); String remark = request.getParameter("remark"); //3.执行更新 fruitDAO.updateFruit(new Fruit(fid, fname, price, fcount, remark)); return "redirect:fruit.do";//只负责返回这个字符串 }
我们将把所以的获取参数的方式从这里面删除.只保留业务代码
private String update(Integer fid, String fname, Integer price, Integer fcount, String remark) throws ServletException { //3.执行更新 fruitDAO.updateFruit(new Fruit(fid, fname, price, fcount, remark)); //4.资源跳转 return "redirect:fruit.do";//只负责返回这个字符串 }
-
-
将edit()代码也修改为相同的形式
private String edit(Integer fid, HttpServletRequest request) {
if (fid != null) {
Fruit fruit = fruitDAO.getFruitByFid(fid);
request.setAttribute("fruit", fruit);
// super.processTemplate("edit", request, response);
return "edit";
}
return "error";
}
- 将del()代码也这样修改
private String del(Integer fid) {
if (fid!=null) {
fruitDAO.delFruit(fid);//删除
//super.processTemplate("index",request,response);
// response.sendRedirect("fruit.do");
return "redirect:fruit.do";//只负责返回这个字符串
}
return "error";
}
-
将add()代码也这样修改
private String add(String fname,Integer price,Integer fcount,String remark) { Fruit fruit = new Fruit(0, fname, price, fcount, remark); fruitDAO.addFruit(fruit); // response.sendRedirect("fruit.do"); return "redirect:fruit.do";//只负责返回这个字符串 }
-
下面来修改index()方法
private String index(String oper, String keyword, Integer pageNo, HttpServletRequest request) {
HttpSession session = request.getSession();
if (StringUtil.isNotEmpty(oper) && "search".equals(oper)) {
pageNo = 1;
if (StringUtil.isEmpty(keyword)) {
keyword = "";
}
session.setAttribute("keyword", keyword);
} else {
Object keywordObj = session.getAttribute("keyword");
if (keywordObj != null) {
keyword = (String) keywordObj;
} else {
keyword = "";
}
}
// 重新更新当前页的值
session.setAttribute("pageNo", pageNo);
FruitDAO fruitDAO = new FruitDAOImpl();
List<Fruit> fruitList = fruitDAO.getFruitList(keyword, pageNo);
session.setAttribute("fruitList", fruitList);
//总记录条数
int fruitCount = fruitDAO.getFruitCount(keyword);
//总页数
int pageCount = (fruitCount + 5 - 1) / 5;
session.setAttribute("pageCount", pageCount);
return "index";
}
-
FruitController类修改完了,我们要开始进行修改中央控制器了
-
首先我们需要先通过这条反射语句
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();//通过反射获取该类的全部方法
获取所有的类当中的方法的参数名称.