ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

四,手写SpringMVC框架,业务层-什么是耦合/依赖?如何解決

2022-08-17 21:00:09  阅读:123  来源: 互联网

标签:String printStackTrace SpringMVC 解決 bean catch import 手写 id


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中的代码

package com.hy.controller;

 

import com.hy.service.IEmpService;

import com.hy.service.impl.EmpServiceImpl;

 

public class EmpController {

private IEmpService empService = new EmpServiceImpl();

 

public void add(String ename,String pwd) {

try {

boolean flag = empService.reg(ename, pwd);

} catch (Exception e) {

e.printStackTrace();

}

}

 

public String index() {

System.out.println("EmpController...index");

return "forward:/WEB-INF/emp/index.jsp";

}

 

public String login(String ename,String pwd) {

System.out.printf("EmpController的login方法获取的参数值ename=%s,pwd=%s",ename,pwd);

return "redirect:emp.do?ac=index";

}

 

public String 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中有new EmpServiceImpl( ) ; 这么new的会就表示和下层的EmpServiceImpl有关系了。

 

 

 

 

 

 

 

 

6. 如何解决耦合和依赖?

IOC-反转控制/ DI-依赖注入

6.1 第一步,将=new 删掉

 

 

 

 

 

 

 

 

6.2 第二步,解决空指针的问题

6.2.1 编写applicationContext.xml配置文件,

在applicationContext.xml再写两行配置文件,在当前的整个配置文件中配置了三个bean,这三个bean就是对应了三个组件。下一步,计划在系统启动的时候它就会把这三个组件准备好,放在一个容器里面,谁需要的时候就给谁用

<?xml version="1.0" encoding="UTF-8"?>

 

<beans>

<!--

这个bean标签的作用是,id中的值,要和将来和ServletPath

中路径的名做对应,emp对应的就要EmpController这个类来处理。

 -->

<bean id="emp" class="com.hy.controller.EmpController"/>

 

<bean id="empService" class="com.hy.service.impl.EmpServiceImpl"/>

 

<bean id="empDao" class="com.hy.dao.impl.EmpDaoImpl"/>

</beans>

 

6.2.2 新建一个接口 BeanFactory & 实现类ClassPathXMLApplicationContext

 

 

 

 

 

 

 

 

 

6.2.3 ClassPathXMLApplicationContext的代码

package com.hy.io;

 

import java.io.IOException;

import java.io.InputStream;

import java.util.concurrent.ConcurrentHashMap;

 

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

 

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

 

public class ClassPathXMLApplicationContext implements BeanFactory {

private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();

 

// 在默认构造方法中加载配置文件

public ClassPathXMLApplicationContext() {

 

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 (int i = 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");

 

boolean flag = map.containsKey(id);

 

if(flag == true)

return;

 

Class clazz = 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

public Object getBean(String id) {

return map.get(id);

}

 

public static void main(String[] args) {

ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext();

}

}

 

运行main方法测试一下。

 

6.2.4 回到DispatcherServlet修改代码

package com.hy.servlet;

 

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.lang.reflect.Parameter;

 

import javax.servlet.ServletConfig;

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.hy.io.BeanFactory;

import com.hy.io.ClassPathXMLApplicationContext;

import com.hy.utils.StringUtil;

 

@WebServlet("*.do")

public class DispatcherServlet extends HttpServlet {

private BeanFactory beanFactory;

 

public DispatcherServlet() {

}

 

@Override

public void init(ServletConfig config) throws ServletException {

super.init(config);

beanFactory = new ClassPathXMLApplicationContext();

}

 

@Override

protected void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, 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

int lastDotIndex = 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 = new Object[parameters.length];

 

for (int i = 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;

} else if (methodReturnStr.startsWith("forward:")) {

String forwardtStr = methodReturnStr.substring("forward:".length());

request.getRequestDispatcher(forwardtStr).forward(request, response);

return;

}

}

return;

}

}

throw new RuntimeException("ac值违法");

}

} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {

e.printStackTrace();

}

}

}

 

 

6.2.5 回到XxxController中,如何给xxxService赋值??

 

我们将new EmpServiceImpl();删除了,去掉了依赖,如何赋值?

而且service层也依赖dao,改成null后,去掉了依赖,如何赋值?

 

 

 

 

 

 

6.2.6 如何解决?

在applicationContext.xml文件中先描述我们需要哪些组件。然后再描述组件与组件之间的依赖关系。XxxController中需要XxxService,XxxService中需要XxxDao。

 

 

 

6.2.7 修改ClassPathXMLApplicationContext代码, 查看获取了xml中的哪些对象

package com.hy.io;

 

import java.io.IOException;

import java.io.InputStream;

import java.util.concurrent.ConcurrentHashMap;

 

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

 

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

 

public class ClassPathXMLApplicationContext implements BeanFactory {

private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();

 

// 在默认构造方法中加载配置文件

public ClassPathXMLApplicationContext() {

 

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 (int i = 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");

 

boolean flag = map.containsKey(id);

 

if (flag == true)

return;

 

Class clazz = 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 (int i = 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 (int j = 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

public Object getBean(String id) {

return map.get(id);

}

 

public static void main(String[] args) {

ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext();

}

}

 

 

6.3 正式组装bean之间的依赖关系

package com.hy.io;

 

import java.io.IOException;

import java.io.InputStream;

import java.lang.reflect.Field;

import java.util.concurrent.ConcurrentHashMap;

 

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

 

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

 

public class ClassPathXMLApplicationContext implements BeanFactory {

private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();

 

// 在默认构造方法中加载配置文件

public ClassPathXMLApplicationContext() {

 

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 (int i = 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");

 

boolean flag = map.containsKey(id);

 

if (flag == true)

return;

 

Class clazz = 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 (int i = 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 (int j = 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 (int j = 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);

 

//获取该对象的类对象

Class beanClazz = 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

public Object getBean(String id) {

return map.get(id);

}

 

public static void main(String[] args) {

ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext();

}

}

http://127.0.0.1:8080/mymvc4/emp.do?ac=add&ename=aaa&pwd=bbb

 

 

标签:String,printStackTrace,SpringMVC,解決,bean,catch,import,手写,id
来源: https://www.cnblogs.com/lijili/p/16596640.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有