mvc-ioc实现
IOC(Inversion of Control):控制反转
1) 耦合/依赖
依赖指的是某某某离不开某某某
在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。
我们系统架构或者是设计的一个原则是: 高内聚低耦合。
层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况0耦合(就是没有耦合)
2) IOC - 控制反转 / DI - 依赖注入
BeanFactory 接口
public interface BeanFactory {
Object getBean(String id);
}
ClassPathXmlApplicationContext 类
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beanMap = new HashMap<>();
public ClassPathXmlApplicationContext() {
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 beanNodeLists = document.getElementsByTagName("bean");
for (int i = 0; i < beanNodeLists.getLength(); i++) {
Node beanNode = beanNodeLists.item(i);
//判断该节点的类型是否等于元素节点
if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Class beanClass = Class.forName(className);
//创建bean实例
Object beanObj = beanClass.newInstance();
//将bean实例对象保存到map容器中
beanMap.put(beanId, beanObj);
//到目前为止,此处需要注意的是:bean和bean之间的依赖关系还没有设置
}
}
//5.组装bean之间的依赖关系
for (int i = 0; i < beanNodeLists.getLength(); i++) {
Node beanNode = beanNodeLists.item(i);
//判断该节点的类型是否等于元素节点
if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
NodeList beanChildNodeList = beanElement.getChildNodes();
for (int j = 0; j < beanChildNodeList.getLength(); j++) {
Node beanChildNode = beanChildNodeList.item(j);
if (beanChildNode.getNodeType() == Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())) {
Element propertyElement = (Element) beanChildNode;
String propertyName = propertyElement.getAttribute("name");
String propertyRef = propertyElement.getAttribute("ref");
//1.找到propertyRef对应的实例
Object refObj = beanMap.get(propertyRef);
//2.将refObj设置到当前bean对应的实例的property属性上去
Object beanObj = beanMap.get(beanId);
Class beanClass = beanObj.getClass();
Field propertyField = beanClass.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 (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String id) {
return beanMap.get(id);
}
}
FruitController 类
//FruitServlet 改名为 FruitController
public class FruitController{
private FruitService fruitService = null;
private String update(Integer fid,String fname,Integer price,Integer fcount,String remark){
//3.执行更新
fruitService.updateFruit(new Fruit(fid, fname, price, fcount, remark));
//4.资源跳转
//super.processTemplate("index",request,response);
//request.getRequestDispatcher(index.html).forward(request,response);
//此处需要重定向,目的是重新给IndexServlet发请求,重新获取fruitList,然后覆盖到session
//这样index.html页面上显示的session中的数据才是最新的
//response.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
private String edit(Integer fid,HttpServletRequest request){
if (fid != null) {
Fruit fruit = fruitService.getFruitByFid(fid);
request.setAttribute("fruit", fruit);
//super.processTemplate("edit", request, response);
return "edit";
}
return "error";
}
private String del(Integer fid){
if (fid != null) {
fruitService.delFruit(fid);
//response.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
return "error";
}
private String add(String fname,Integer price,Integer fcount,String remark){
Fruit fruit = new Fruit(0, fname, price, fcount, remark);
fruitService.addFruit(fruit);
//response.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
private String index(String oper,String keyword,Integer pageNo,HttpServletRequest request){
HttpSession session = request.getSession();
if (pageNo == null){
pageNo = 1;
}
//如果oper != null 说明是通过表单的查询按钮点击过来的
//如果oper是空的,说明不是通过表单的查询按钮点击过来的
if (StringUtil.isNotEmpty(oper) && "search".equals(oper)) {
//说明是点击表单查询发送过来的请求
//此时,pageNo应该还原为1,keyword应该从请求参数获取
pageNo = 1;
//如果keyword为null,需要设置为空字符串"",否则查询时会拼接成 %null%
//我们期望的是 %%,就是查询所有的数据
if (StringUtil.isEmpty(keyword)) {
keyword = "";
}
//将 keyword 保存(覆盖)到session中
session.setAttribute("keyword", keyword);
} else {
//说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
//此时keyword应该从session作用域获取
//如果不是点击的查询按钮,那么查询是基于session中保存的现有的keyword进行查询
Object keywordobj = session.getAttribute("keyword");
if (keywordobj != null) {
keyword = (String) keywordobj;
} else {
keyword = "";
}
}
//重新更新当前页的值
session.setAttribute("pageNo", pageNo);
List<Fruit> fruitList = fruitService.getFruitList(keyword, pageNo);
session.setAttribute("fruitList", fruitList);
//总记录条数
int pageCount = fruitService.getPageCount(keyword);
/*
总记录条数 总页数
1 1
5 1
6 2
10 2
11 3
fruitCount (fruitCount+5-1)/5
*/
session.setAttribute("pageCount", pageCount);
//此处的视图名称是index
//那么thymeleaf会将这个 逻辑视图 名称对应到 物理视图 名称上去
// //逻辑视图名称:index
//物理视图名称: viw-prefix + 逻辑视图名称 +view-suffix
//所以真实的视图名称是: / index .html
//super.processTemplate("index", request, response);
return "index";
}
}
FruitService 接口
public interface FruitService {
//获取指定页面的库存列表信息
List<Fruit> getFruitList(String keyword, Integer pageNo);
//添加库存记录信息
void addFruit(Fruit fruit);
//根据id查看指定库存记录
Fruit getFruitByFid(Integer fid);
//删除特定库存记录
void delFruit(Integer fid);
//修改特定库存记录
void updateFruit(Fruit fruit);
//获取总页数
Integer getPageCount(String keyword);
}
FruitServiceImpl 类
public class FruitServiceImpl implements FruitService{
private FruitDAO fruitDAO = null;
@Override
public List<Fruit> getFruitList(String keyword, Integer pageNo) {
return fruitDAO.getFruitList(keyword,pageNo);
}
@Override
public void addFruit(Fruit fruit) {
fruitDAO.addFruit(fruit);
}
@Override
public Fruit getFruitByFid(Integer fid) {
return fruitDAO.getFruitByFid(fid);
}
@Override
public void delFruit(Integer fid) {
fruitDAO.delFruit(fid);
}
@Override
public void updateFruit(Fruit fruit) {
fruitDAO.updateFruit(fruit);
}
@Override
public Integer getPageCount(String keyword) {
int count = fruitDAO.getFruitCount(keyword);
int pageCount = (count + 5 - 1) / 5;
return pageCount;
}
}
applicationContext.xml
<?xml version="1.0" encoding="utf-8"?>
<beans>
<bean id="fruitDAO" class="com.atguigu.fruit.dao.impl.FruitDAOImpl"/>
<bean id="fruitService" class="com.atguigu.fruit.service.impl.FruitServiceImpl">
<!-- property标签用来表示属性;name表示属性名;ref表示引用其它bean的id值 -->
<property name="fruitDAO" ref="fruitDAO"/>
</bean>
<!-- 这个bean标签的作用是 将来servletpath中涉及的名字对应的是fruit,那么就要FruitController这个类来处理 -->
<bean id="fruit" class="com.atguigu.fruit.controllers.FruitController">
<property name="fruitService" ref="fruitService"/>
</bean>
</beans>
<!--
Node节点
Element节点
Text 文本节点
<sname>jim</sname>
-->
<!--
1.概念
HTML : 超文本标记语言
XML : 可扩展的标记语言
HTML是XML的一个子集
2.XML包含三个部分:
1) XML声明 , 而且声明这一行代码必须在XML文件的第一行
2) DTD 文档类型定义
3) XML正文
-->