4. 业务层
4.1 MVC模型
MVC:Model(模型),View(视图),Controller(控制器)
视图层:用于做数据的展示以及和用户交互的一个界面=>jsp
控制层:能够接受客户端的请求并且进行请求转发,具体的业务功能还是需要借助模型层组件来完成。CoreServlet=> DispacherServlet + EmpController
模型层:模型分为很多种:
1) 存值的值对象: POJO/VO(value object)/entity/bean-> Emp
2)有数据访问对象:DAO—数据访问对象:xxxDao
3) 有业务模型对象:BO,业务对象 比如:xxxService
4) 数据传输对象:DTO data transfer object
4.1 什么是业务对象4.2 区分业务对象和数据访问对象4.2.1单精度方法
DAO中的方法都是单精度方法 或者称之为细粒度方法。
什么叫单精度?一个方法只考虑一个操作,比如,添加,那就是insert操作。查询那就是select操作。
4.2.2 BO也就是Service层属于业务方法
BO中的方法属于业务方法,但实际的业务是比较复杂的,因此业务方法的粒度是比较粗的
比如:注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。
那么在这个业务方法中包含了多少个DAO方法呢,也就是说注册这个业务功能需要通过调用多个DAO方法的组合调用才能完成注册功能。
4.2.3 注册的功能步骤:
1、检查用户名是否已经被注册—DAO中的select操作。
2、向用户表新增一条新用户记录—DAO的insert操作。
3、向用户积分表新增一条记录(新用户默认初始化积分假如是100分)—DAO中的insert操作
4、向系统消息表新增一条记录(某某新用户注册了,需要根据通讯录信息向他的联系人推送消息)—DAO中的insert操作。
5、向系统日志表新增一条记录(某用户在某IP在某年某月某日某时某分某秒注册)—DAO中的insert操作。
4.3 代码的编写(mymvc4)
4.4 新建IEmpDao&EmpDaoImpl
4.5 新建IEmpService&EmpServiceImpl,写一个reg方法
4.6 EmpController中的代码
packagecom.hy.controller; importcom.hy.service.IEmpService; importcom.hy.service.impl.EmpServiceImpl; publicclassEmpController { privateIEmpService empService= newEmpServiceImpl(); publicvoidadd(String ename,String pwd) { try{ booleanflag= empService.reg(ename, pwd); } catch(Exception e) { e.printStackTrace(); } } publicString index() { System.out.println(“EmpController…index”); return“forward:/WEB-INF/emp/index.jsp”; } publicString login(String ename,String pwd) { System.out.printf(“EmpController的login方法获取的参数值ename=%s,pwd=%s”,ename,pwd); return“redirect:emp.do?ac=index”; } publicString delete(Integer eid) { if(eid!=null) { System.out.println(“EmpController eid==”+eid); //empDao.delete(eid); return“forward:xxx”; } return“forward:error.xxx”; } } |
5. 什么是耦合/依赖
耦合/依赖 :依赖指的是谁离不开谁,这叫依赖。比如:你离不开你女朋友。你依赖你女朋友
在我们系统当中的每个层之间,层与层之间也存在依赖。比如:Controller层必须依赖Service层,例如:现在将Service层EmpServiceImpl删除了,然后EmpController层就会报错。
同样,Service层依赖Dao层。
依赖指的是 某某某 离不开 某某某
在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。
我们系统架构或是设计的一个原则就是:高内聚 低耦合。
层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的。
而所谓的低耦合,就是我们熟称的炮友。
我想做到的是什么??删除EmpServiceImpl, EmpController不报错,EmpController中有newEmpServiceImpl() ;这么new的会就表示和下层的EmpServiceImpl有关系了。
6.如何解决耦合和依赖?
IOC–反转控制/DI–依赖注入
6.1 第一步,将=new 删掉
6.2 第二步,解决空指针的问题6.2.1 编写applicationContext.xml配置文件,
在applicationContext.xml再写两行配置文件,在当前的整个配置文件中配置了三个bean,这三个bean就是对应了三个组件。下一步,计划在系统启动的时候,它就会把这三个组件准备好,放在一个容器里面,谁需要的时候就给谁用。
<?xmlversion=“1.0”encoding=“UTF-8”?> <!– 这个bean标签的作用是,id中的值,要和将来和ServletPath 中路径的名做对应,emp对应的就要EmpController这个类来处理。 –> <beanid=“emp”class=“com.hy.controller.EmpController”/> <beanid=“empService”class=“com.hy.service.impl.EmpServiceImpl”/> <beanid=“empDao”class=“com.hy.dao.impl.EmpDaoImpl”/> |
6.2.2 新建一个接口 BeanFactory& 实现类ClassPathXMLApplicationContext
6.2.3 ClassPathXMLApplicationContext的代码
packagecom.hy.io; importjava.io.IOException; importjava.io.InputStream; importjava.util.concurrent.ConcurrentHashMap; importjavax.xml.parsers.DocumentBuilder; importjavax.xml.parsers.DocumentBuilderFactory; importjavax.xml.parsers.ParserConfigurationException; importorg.w3c.dom.Document; importorg.w3c.dom.Element; importorg.w3c.dom.Node; importorg.w3c.dom.NodeList; importorg.xml.sax.SAXException; publicclassClassPathXMLApplicationContext implementsBeanFactory { privateConcurrentHashMap map= newConcurrentHashMap(); // 在默认构造方法中加载配置文件 publicClassPathXMLApplicationContext() { try{ InputStream inputStream= this.getClass().getClassLoader().getResourceAsStream(“applicationContext.xml”); // 1,创建DocumentBuilderFactory工厂对象 DocumentBuilderFactory documentBuilderFactory= DocumentBuilderFactory.newInstance(); // 2,创建DocumentBuilder对象 DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); // 3,得到Document对象( 注意导入org.w3c.dom包中的) Document document= documentBuilder.parse(inputStream); // 4,获得所有的Bean标签 NodeList nodeList= document.getElementsByTagName(“bean”); for(inti= 0, len= nodeList.getLength(); i< len; i++) { Node node= nodeList.item(i); System.out.println(node.getNodeType() );//1,1,1 if( node.getNodeType() == node.ELEMENT_NODE) { Element element= (Element)node; String id= element.getAttribute(“id”); String className= element.getAttribute(“class”); booleanflag= map.containsKey(id); if(flag== true) return; Classclazz= Class.forName(className); Object o= clazz.newInstance(); map.put(id, o); } } } catch(ParserConfigurationException e) { e.printStackTrace(); } catch(SAXException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } catch(ClassNotFoundException e) { e.printStackTrace(); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); } } @Override publicObject getBean(String id) { returnmap.get(id); } publicstaticvoidmain(String[] args) { ClassPathXMLApplicationContext applicationContext= newClassPathXMLApplicationContext(); } } |
运行main方法测试一下。
6.2.4 回到DispatcherServlet修改代码
packagecom.hy.servlet; importjava.io.IOException; importjava.lang.reflect.InvocationTargetException; importjava.lang.reflect.Method; importjava.lang.reflect.Parameter; importjavax.servlet.ServletConfig; importjavax.servlet.ServletException; importjavax.servlet.annotation.WebServlet; importjavax.servlet.http.HttpServlet; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importcom.hy.io.BeanFactory; importcom.hy.io.ClassPathXMLApplicationContext; importcom.hy.utils.StringUtil; @WebServlet(“*.do”) publicclassDispatcherServlet extendsHttpServlet { privateBeanFactory beanFactory; publicDispatcherServlet() { } @Override publicvoidinit(ServletConfig config) throwsServletException { super.init(config); beanFactory= newClassPathXMLApplicationContext(); } @Override protectedvoidservice(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException { // 设置编码 request.setCharacterEncoding(“UTF-8”); response.setCharacterEncoding(“UTF-8”); response.setContentType(“text/html;charset=UTF-8”); // 假设url是: http://localhost:8080/mymvc2/hello.do // ServletPath是Servlet的访问路径: /hello.do // 思路是: // 第1步: /hello.do -> hello 或者 /book.do -> book // 第2步: hello -> HelloController 或者 book -> BookController String servletPath= request.getServletPath(); // /hello.do intlastDotIndex= servletPath.lastIndexOf(“.do”); servletPath= servletPath.substring(1, lastDotIndex); // hello // 通过ServletPath获取对应的Controller对象 // Object xxxController = map.get(servletPath); Object xxxController= beanFactory.getBean(servletPath); String ac= request.getParameter(“ac”); System.out.println(“=======ac ===”+ ac+ “======”); if(StringUtil.isEmpty(ac)) ac= “index”; String methodReturnStr= null; try{ // 这里只能try…catch异常,因为在重写的方法里,不能抛出比父类更大的异常 Method[] methods= xxxController.getClass().getDeclaredMethods(); if(methods!= null) { for(Method method: methods) { if(ac.equals(method.getName())) { // 1,统一获取请求参数 // 1.1 获取当前方法的参数,返回参数数组 Parameter[] parameters= method.getParameters(); // 1.2 有几个参数就需要准备同等容量的Object类型的数组。这个数组用来存放参数的值得 Object[] parameterValues= newObject[parameters.length]; for(inti= 0, len= parameters.length; i< len; i++) { Parameter parameter= parameters[i]; // 1.3 从请求中获取参数的值 String parameterValue= request.getParameter(parameter.getName()); /** * 注意,这里没有考虑 复选框的情况,因为复选框name相同, * 打了好几个勾,一提交,返回给我们值的是一个数组 获取的方法: * request.getParameterValues(name); */ // 1.5 EmpController中delete方法的参数需要的是一个Integer类型, // 通过反射机制我们该方法需要的类型Parameter是Integer, // 但是前台传递到后台的是字符串”1”,而不是数字1,所以需要进行类型转换。 String typeName= parameter.getType().getName(); System.out.println(“DispatcherServlet ==== typeName”+typeName); //注意:这里一定要先将String 转成 Object Object parameterObj= parameterValue; if(parameterObj!= null) { //注意:这里如果需要完善, 还需要写Float,Double等类型 if(“java.lang.Integer”.equals(typeName)) { parameterObj= Integer.parseInt(parameterValue); } } // 1.4 将获取的参数值保存在Object类型的数组当中 //parameterValues[i] = parameterValue; parameterValues[i] = parameterObj; } // 2. xxxController中的方法调用 // Object returnObj = method.invoke(xxxController, request, response); Object returnObj= method.invoke(xxxController,parameterValues); // 3, 视图跳转处理 if(returnObj!= null) { methodReturnStr= (String) returnObj; if(methodReturnStr.startsWith(“redirect:”)) { String redirectStr= methodReturnStr.substring(“redirect:”.length()); response.sendRedirect(request.getContextPath() + “/”+ redirectStr); return; } elseif(methodReturnStr.startsWith(“forward:”)) { String forwardtStr= methodReturnStr.substring(“forward:”.length()); request.getRequestDispatcher(forwardtStr).forward(request, response); return; } } return; } } thrownewRuntimeException(“ac值违法“); } } catch(SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } } |
6.2.5 回到XxxController中,如何给xxxService赋值??
我们将newEmpServiceImpl();删除了,去掉了依赖,如何赋值?
而且service层也依赖dao,改成null后,去掉了依赖,如何赋值?
6.2.6 如何解决?
在applicationContext.xml文件中先描述我们需要哪些组件。然后再描述组件与组件之间的依赖关系。XxxController中需要XxxService,XxxService中需要XxxDao。
6.2.7 修改ClassPathXMLApplicationContext代码, 查看获取了xml中的哪些对象
packagecom.hy.io; importjava.io.IOException; importjava.io.InputStream; importjava.util.concurrent.ConcurrentHashMap; importjavax.xml.parsers.DocumentBuilder; importjavax.xml.parsers.DocumentBuilderFactory; importjavax.xml.parsers.ParserConfigurationException; importorg.w3c.dom.Document; importorg.w3c.dom.Element; importorg.w3c.dom.Node; importorg.w3c.dom.NodeList; importorg.xml.sax.SAXException; publicclassClassPathXMLApplicationContext implementsBeanFactory { privateConcurrentHashMap map= newConcurrentHashMap(); // 在默认构造方法中加载配置文件 publicClassPathXMLApplicationContext() { try{ InputStream inputStream= this.getClass().getClassLoader().getResourceAsStream(“applicationContext.xml”); // 1,创建DocumentBuilderFactory工厂对象 DocumentBuilderFactory documentBuilderFactory= DocumentBuilderFactory.newInstance(); // 2,创建DocumentBuilder对象 DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); // 3,得到Document对象( 注意导入org.w3c.dom包中的) Document document= documentBuilder.parse(inputStream); // 4,获得所有的Bean标签 NodeList nodeList= document.getElementsByTagName(“bean”); for(inti= 0, len= nodeList.getLength(); i< len; i++) { Node node= nodeList.item(i); System.out.println(node.getNodeType());// 1,1,1 if(node.getNodeType() == node.ELEMENT_NODE) { Element element= (Element) node; String id= element.getAttribute(“id”); String className= element.getAttribute(“class”); booleanflag= map.containsKey(id); if(flag== true) return; Classclazz= Class.forName(className); // 创建bean对象 Object o= clazz.newInstance(); // 将bean对象存储到容器当中 map.put(id, o); // 到目前为止,我们将所有的bean,已经实例化(new了一个对象), // 并且存放到了容器当中,但是bean与bean对象之间的依赖关系还没有处理 } } System.out.println(“=================”); // 5, 组装bean之间的依赖关系,拿到bean对象之后,如果里面有property标签则进行组装 for(inti= 0, len= nodeList.getLength(); i< len; i++) { Node node= nodeList.item(i); if(node.getNodeType() == Node.ELEMENT_NODE) { Element element= (Element) node; String id= element.getAttribute(“id”); // //element 就是获取的bean对象,通过getChildNodes()方法 //来获取这个对象有三个子节点,1和3是文本节点 NodeList childNodes= element.getChildNodes(); // System.out.println(childNodes.getLength());// 3,5,0 // //if (i == 1) { //查看第二个bean标签的5个子元素的类型分别是什么, // for (intj = 0; j < childNodes.getLength(); j++) { // //NodeType为 3,8,3,1,3, // //Node.TEXT_NODE = 3; // //Node.COMMENT_NODE = 8; // //Node.ELEMENT_NODE = 1; // System.out.print(childNodes.item(j).getNodeType()+”,”); // } //} } } } catch(ParserConfigurationException e) { e.printStackTrace(); } catch(SAXException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } catch(ClassNotFoundException e) { e.printStackTrace(); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); } } @Override publicObject getBean(String id) { returnmap.get(id); } publicstaticvoidmain(String[] args) { ClassPathXMLApplicationContext applicationContext= newClassPathXMLApplicationContext(); } } |
6.3 正式组装bean之间的依赖关系
packagecom.hy.io; importjava.io.IOException; importjava.io.InputStream; importjava.lang.reflect.Field; importjava.util.concurrent.ConcurrentHashMap; importjavax.xml.parsers.DocumentBuilder; importjavax.xml.parsers.DocumentBuilderFactory; importjavax.xml.parsers.ParserConfigurationException; importorg.w3c.dom.Document; importorg.w3c.dom.Element; importorg.w3c.dom.Node; importorg.w3c.dom.NodeList; importorg.xml.sax.SAXException; publicclassClassPathXMLApplicationContext implementsBeanFactory { privateConcurrentHashMap map= newConcurrentHashMap(); // 在默认构造方法中加载配置文件 publicClassPathXMLApplicationContext() { try{ InputStream inputStream= this.getClass().getClassLoader().getResourceAsStream(“applicationContext.xml”); // 1,创建DocumentBuilderFactory工厂对象 DocumentBuilderFactory documentBuilderFactory= DocumentBuilderFactory.newInstance(); // 2,创建DocumentBuilder对象 DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); // 3,得到Document对象( 注意导入org.w3c.dom包中的) Document document= documentBuilder.parse(inputStream); // 4,获得所有的Bean标签 NodeList nodeList= document.getElementsByTagName(“bean”); for(inti= 0, len= nodeList.getLength(); i< len; i++) { Node node= nodeList.item(i); System.out.println(node.getNodeType());// 1,1,1 if(node.getNodeType() == node.ELEMENT_NODE) { Element element= (Element) node; String id= element.getAttribute(“id”); String className= element.getAttribute(“class”); booleanflag= map.containsKey(id); if(flag== true) return; Classclazz= Class.forName(className); // 创建bean对象 Object o= clazz.newInstance(); // 将bean对象存储到容器当中 map.put(id, o); // 到目前为止,我们将所有的bean,已经实例化(new了一个对象), // 并且存放到了容器当中,但是bean与bean对象之间的依赖关系还没有处理 } } System.out.println(“=================”); // 5, 组装bean之间的依赖关系,拿到bean对象之后,如果里面有property标签则进行组装 for(inti= 0, len= nodeList.getLength(); i< len; i++) { Node node= nodeList.item(i); if(node.getNodeType() == Node.ELEMENT_NODE) { Element element= (Element) node; String id= element.getAttribute(“id”); // // element 就是获取的bean对象,通过getChildNodes()方法 // 来获取这个对象有三个子节点,1和3是文本节点 NodeList childNodes= element.getChildNodes(); // System.out.println(childNodes.getLength());// 3,5,0 // // if (i == 1) { //查看第二个bean标签的5个子元素的类型分别是什么, // for (intj = 0; j < childNodes.getLength(); j++) { // //NodeType为 3,8,3,1,3, // //Node.TEXT_NODE = 3; // //Node.COMMENT_NODE = 8; // //Node.ELEMENT_NODE = 1; // System.out.print(childNodes.item(j).getNodeType()+”,”); // } // } for(intj= 0; j< childNodes.getLength(); j++) { Node childNode= childNodes.item(j); if(childNode.getNodeType() == Node.ELEMENT_NODE && “property”.equals(childNode.getNodeName())) { Element propertyElement= (Element)childNode; //获取其name属性和ref属性 String propertyName= propertyElement.getAttribute(“name”); String propertyRef= propertyElement.getAttribute(“ref”); //找到ref对应的实例对象 Object refObj= map.get(propertyRef); //当refObj设置到当前bean对应的对象的property属性上来 Object beanObj= map.get(id); //获取该对象的类对象 ClassbeanClazz= beanObj.getClass(); //获得该类对象的属性 Field propertyField= beanClazz.getDeclaredField(propertyName); //设置其可访问性 propertyField.setAccessible(true); propertyField.set(beanObj, refObj); } } } } } catch(ParserConfigurationException e) { e.printStackTrace(); } catch(SAXException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } catch(ClassNotFoundException e) { e.printStackTrace(); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); } catch(NoSuchFieldException e) { e.printStackTrace(); } catch(SecurityException e) { e.printStackTrace(); } } @Override publicObject getBean(String id) { returnmap.get(id); } publicstaticvoidmain(String[] args) { ClassPathXMLApplicationContext applicationContext= newClassPathXMLApplicationContext(); } } |
http://127.0.0.1:8080/mymvc4/emp.do?ac=add&ename=aaa&pwd=bbb