Java web 2022跟学尚硅谷(五) 后端基础

2.2MVC优化.依赖注入和控制反转

优化

类图

类图

FruitController

package com.atguigu.fruit.controllers;

import com.atguigu.fruit.pojo.Fruit;
import com.atguigu.fruit.service.impl.FruitServiceImpl;
import com.atguigu.uils.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

/**
 * @ClassName: FruitServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/6
 */
public class FruitController {

    /**
     * 接口的多态
     */
    private FruitServiceImpl fruitServiceimpl = null;
    //private FruitServiceInterface fruitServiceInterface = new FruitServiceImpl();

    private String index(String oper, String keyword, Integer pageNumber, HttpServletRequest request) {
        List<Fruit> fruitList = null;
        // 分页查询(增加参数pageNumber)
        int pageCount = 0;
        HttpSession session = request.getSession();

        if (null == pageNumber) {
            pageNumber = 1;
        }
        // 模糊查询
        if (StringUtils.isNotEmpty(oper) && "search".equals(oper)) {
            // 相当于是模糊查询
            if (StringUtils.isEmpty(keyword)) {
                keyword = "";
            }
            pageNumber = 1;
        } else {
            // 说明此处不是模糊查询,此时keyword应该从session作用域获取

            // 分页查询(增加参数pageNumber)
            Object keywordObj = session.getAttribute("keyword");
            if (null != keywordObj) {
                keyword = (String) keywordObj;
            } else {
                keyword = "";
            }
        }
        // 将keyword从session作用域获取
        session.setAttribute("keyword", keyword);

        fruitList = fruitServiceimpl.getFruitList(pageNumber, keyword);


        // 非分页,显示全部,更新当前页的值
        session.setAttribute("pageNumber", pageNumber);

        // 获取总条数
        pageCount = fruitServiceimpl.getFruitCount(keyword);
        // 获取总页数pageCount
        session.setAttribute("pageCount", pageCount);

        // 保存到session作用域
        //HttpSession session = request.getSession();
        session.setAttribute("fruitList", fruitList);

        // 此处的视图名称是index
        // thymeleaf会将这个逻辑视图名称对应到物理视图名称中去
        // 物理视图名称 = view-prefix + 逻辑视图名称 + view-suffix
        // 所以真实视图名称: /index.html
        //super.processTemplate("index", request, response);
        return "index";
    }

    private String add(String fname, Integer price, Integer fcount, String remark, HttpServletRequest request) throws IOException {
        request.setCharacterEncoding("UTF-8");
        // 判断是doGet还是doPost
        //if (StringUtils.isEmpty(request.getParameter("fname"))
        //        || StringUtils.isEmpty(request.getParameter("price"))
        //        || StringUtils.isEmpty(request.getParameter("fcount"))) {
        //    //processTemplate("add", request, response);
        //    return "add";
        //}
        if (StringUtils.isEmpty(fname)
                || null == price
                || null == fcount) {
            //processTemplate("add", request, response);
            return "add";
        }
        fruitServiceimpl.addFruit(new Fruit(0, fname, price, fcount, remark));
        //response.sendRedirect("fruit.do");
        return "redirect:fruit.do";

    }

    private String del(Integer fid) {
        if (null != fid) {
            //fruitService
            fruitServiceimpl.delFruitByFid(fid);
            //response.sendRedirect("fruit.do");
            return "redirect:fruit.do";
        }
        return "error";
    }

    private String edit(Integer fid, HttpServletRequest request) {
        if (null != fid) {
            Fruit fruit = fruitServiceimpl.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
            //processTemplate("edit", request, response);
            return "edit";
        }
        return "error";
    }

    private String update(Integer fid, String fname, Integer price, Integer fcount, String remark) {
        //  执行更新
        fruitServiceimpl.updateFruitByFid(new Fruit(fid, fname, price, fcount, remark));
        // 资源跳转
        //response.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }
}

FruitServiceInterface

package com.atguigu.fruit.service;

import com.atguigu.fruit.pojo.Fruit;

import java.util.List;

/**
 * @InterfaceName: FruitServiceInterface
 * @Description:
 * @Author: wty
 * @Date: 2022/12/8
 */

public interface FruitServiceInterface {
    // 获取指定页面的库存列表信息
    public List<Fruit> getFruitList(Integer pageNumber, String keyword);

    // 添加库存记录
    public boolean addFruit(Fruit fruit);

    //根据id查看指定库存记录
    public Fruit getFruitByFid(Integer fid);

    // 获取总页数
    public Integer getFruitCount(String keyword);

    // 通过fid删除
    public boolean delFruitByFid(Integer fid);

    // 修改库存记录
    boolean updateFruitByFid(Fruit fruit);
}

FruitServiceImpl

package com.atguigu.fruit.service.impl;

import com.atguigu.fruit.dao.FruitDAO;
import com.atguigu.fruit.pojo.Fruit;
import com.atguigu.fruit.service.FruitServiceInterface;

import java.util.List;

/**
 * @ClassName: FruitServiceImpl
 * @Description:
 * @Author: wty
 * @Date: 2022/12/8
 */

public class FruitServiceImpl implements FruitServiceInterface {
    //private FruitDAO fruitDAO = new FruitDAO();
    private FruitDAO fruitDAO = null;

    /**
     * @param
     * @return java.util.List<com.atguigu.fruit.pojo.Fruit>
     * @description 支持模糊和分页查询
     * @param: pageNumber
     * @param: keyword
     * @date 2022/12/8 0:24
     * @author wty
     **/
    @Override
    public List<Fruit> getFruitList(Integer pageNumber, String keyword) {
        String sqlStr = "select * from t_fruit where fname like ? or remark like ? limit ?,5";
        return fruitDAO.queryMulti(sqlStr, Fruit.class, "%" + keyword + "%", "%" + keyword + "%", (pageNumber - 1) * 5);
    }

    /**
     * @param
     * @return boolean
     * @description 添加库存记录
     * @param: fruit
     * @date 2022/12/8 0:24
     * @author wty
     **/
    @Override
    public boolean addFruit(Fruit fruit) {
        String sqlStr = "insert into t_fruit values(0,?,?,?,?)";
        int affectedrows = fruitDAO.dml(sqlStr, fruit.getFname(), fruit.getPrice(), fruit.getFcount(), fruit.getRemark());

        return affectedrows > 0;
    }

    /**
     * @param
     * @return com.atguigu.fruit.pojo.Fruit
     * @description 通过fid获取一行库存记录
     * @param: fid
     * @date 2022/12/8 0:23
     * @author wty
     **/
    @Override
    public Fruit getFruitByFid(Integer fid) {
        String sqlStr = "select * from t_fruit where fid = ?";
        return fruitDAO.querySingle(sqlStr, Fruit.class, fid);
    }

    /**
     * @param
     * @return java.lang.Integer
     * @description 获取总页数pageCount
     * @param: keyword
     * @date 2022/12/8 0:23
     * @author wty
     **/
    @Override
    public Integer getFruitCount(String keyword) {
        String sqlStr = "select count(*) from t_fruit where fname like ? or remark like ?";
        Object o = fruitDAO.queryScalar(sqlStr, "%" + keyword + "%", "%" + keyword + "%");

        Integer i = 0;
        if (o instanceof Long) {
            i = ((Long) o).intValue();
        }
        Integer pageCount = (i + 5 - 1) / 5;

        return pageCount;
    }

    /**
     * @param
     * @return boolean
     * @description 通过fid删除某行记录
     * @param: fid
     * @date 2022/12/8 0:32
     * @author wty
     **/
    @Override
    public boolean delFruitByFid(Integer fid) {
        String sqlStr = "delete from t_fruit where fid = ?";
        int affectedrows = fruitDAO.dml(sqlStr, fid);
        return affectedrows > 0;
    }

    /**
     * @param
     * @return boolean
     * @description 修改水果库存记录
     * @param: fruit
     * @date 2022/12/8 0:32
     * @author wty
     **/
    @Override
    public boolean updateFruitByFid(Fruit fruit) {
        String sqlStr = "update t_fruit set fname = ?, price = ?, fcount = ?, remark = ? where fid = ? ";
        int affectedrows = fruitDAO.dml(sqlStr, fruit.getFname(), fruit.getPrice(), fruit.getFcount(), fruit.getRemark(), fruit.getFid());
        return affectedrows > 0;
    }
}

BeanFactory

package com.atguigu.myssm.io;

/**
 * @InterfaceName: BeanFactory
 * @Description:
 * @Author: wty
 * @Date: 2022/12/8
 */

public interface BeanFactory {
    public Object getBean(String id);
}

ClassPathXmlApplicationContext

package com.atguigu.myssm.io;

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;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: ClassPathXmlApplicationContext
 * @Description:
 * @Author: wty
 * @Date: 2022/12/8
 */

public class ClassPathXmlApplicationContext implements BeanFactory {
    private Map<String, Object> beanMap = new HashMap<>();

    @Override
    public Object getBean(String id) {
        return beanMap.get(id);
    }

    /**
     * @param
     * @return
     * @description //构造方法
     * @date 2022/12/8 10:49
     * @author wty
     **/
    public ClassPathXmlApplicationContext() {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
        // 1.创建DocumentBuilderFactory
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        // 2.创建DocumentBuilder
        try {
            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");

                    // 创建bean对象和bean实例
                    Class<?> beanClass = Class.forName(className);
                    // 类对象
                    Object beanObject = beanClass.newInstance();

                    // 加入servletContext
                    //Field servletContextField = beanObj.getDeclaredField("servletContext");
                    //servletContextField.setAccessible(true);
                    //servletContextField.set(o, this.getServletContext());

                    //Method setServletContext = beanObj.getDeclaredMethod("setServletContext", ServletContext.class);
                    //setServletContext.invoke(o, this.getServletContext());

                    // 将bean对象保存到beanMap中
                    beanMap.put(beanId, beanObject);

                    // 到目前位置需要注意bean之间的依赖关系
                }
            }

            // 5. 组装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");

                    NodeList beanchildNodeList = beanElement.getChildNodes();
                    System.out.println(beanchildNodeList.getLength());

                    for (int j = 0; j < beanchildNodeList.getLength(); j++) {
                        Node beanChildNode = beanchildNodeList.item(j);
                        /**
                         *
                         * Node 结点
                         *     Element 元素节点 sname
                         *     Text 文本节点 jim
                         * <sname>jim</sname>
                         *
                         */
                        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对应的实例propertyName
                            Object refObject = beanMap.get(propertyref);
                            // 2.将refObject设置到当前bean对应的实例的property属性上
                            Object beanObject = beanMap.get(beanId);

                            Class<?> beanClass = beanObject.getClass();
                            Field propertyField = beanClass.getDeclaredField(propertyName);
                            propertyField.setAccessible(true);
                            propertyField.set(beanObject, refObject);
                        }
                    }

                }
            }


        } catch (ParserConfigurationException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

DispatcherServlet

package com.atguigu.myssm.myspringmvc;

import com.atguigu.myssm.io.BeanFactory;
import com.atguigu.myssm.io.ClassPathXmlApplicationContext;
import com.atguigu.uils.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @ClassName: DispatcherServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/7
 */
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
    private BeanFactory beanFactory = null;

    public DispatcherServlet() {

    }

    /**
     * @param
     * @return void
     * @description Servlet初始化阶段,并且初始化BeanFactory对象
     * @date 2022/12/8 10:54
     * @author wty
     **/
    @Override
    public void init() throws ServletException {
        super.init();
        beanFactory = new ClassPathXmlApplicationContext();
    }

    @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

        String servletPath = request.getServletPath();
        /// hello.do
        System.out.println(servletPath);

        // 1.字符串截取 hello.do 得到 hello
        servletPath = servletPath.substring(1, servletPath.length() - 3);
        System.out.println(servletPath);

        // 2. hello 和 helloController对应上
        Object contorllerBeanObject = beanFactory.getBean(servletPath);


        // 下面的逻辑来自于FruitController
        String operate = request.getParameter("operate");
        if (StringUtils.isEmpty(operate)) {
            operate = "index";
        }

        try {
            Method declaredMethods[] = contorllerBeanObject.getClass().getDeclaredMethods();
            for (Method declaredMethod : declaredMethods) {
                if (operate.equals(declaredMethod.getName())) {
                    // 1.统一获取请求参数
                    // 获取当前方法的所有参数,返回参数数组
                    Parameter[] parameters = declaredMethod.getParameters();
                    // parametersobjectsValue用来存放参数的值
                    Object[] parametersobjectsValue = new Object[parameters.length];
                    for (int i = 0; i < parameters.length; i++) {
                        Parameter parameter = parameters[i];
                        String parameterName = parameter.getName();

                        // 如果参数名是request、response、session那么单独处理
                        if ("request".equals(parameterName)) {
                            parametersobjectsValue[i] = request;
                        } else if ("response".equals(parameterName)) {
                            parametersobjectsValue[i] = response;
                        } else if ("session".equals(parameterName)) {
                            parametersobjectsValue[i] = request.getSession();
                        } else {
                            // 从请求中获取参数值
                            String parameterValue = request.getParameter(parameterName);

                            //当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2
                            // 最后的2在parameterValue中是"2"会报错argument type mismatch
                            String typeName = parameter.getType().getName();
                            if ("java.lang.String".equals(typeName)) {
                                parametersobjectsValue[i] = parameterValue;
                            } else if (null != parameterValue && "java.lang.Integer".equals(typeName)) {
                                parametersobjectsValue[i] = Integer.parseInt(parameterValue);
                            } else {
                                parametersobjectsValue[i] = parameterValue;
                            }
                        }
                    }
                    // 2.controller组件中的方法调用
                    declaredMethod.setAccessible(true);
                    Object o = declaredMethod.invoke(contorllerBeanObject, parametersobjectsValue);

                    // 3.视图处理:
                    String methodReturnStr = (String) o;
                    if (methodReturnStr.startsWith("redirect")) {
                        // 比如 redirect:fruit.do
                        // 截取后只想要 fruit.do
                        String redirectStr = methodReturnStr.substring("redirect:".length());
                        response.sendRedirect(redirectStr);
                    } else {
                        // 比如 edit
                        super.processTemplate(methodReturnStr, request, response);
                    }
                } else {
                    //throw new RuntimeException("operate值非法!");
                }
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
// 常间错误 argument type mismatch
// 当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2

applicationContext.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans>
    <bean id="fruitDAO" class="com.atguigu.fruit.dao.FruitDAO"></bean>
    <bean id="fruitServiceimpl" class="com.atguigu.fruit.service.impl.FruitServiceImpl">
        <property name="fruitDAO" ref="fruitDAO"></property>
    </bean>
    <!-- 这个bean标签的作用是,将来servletpath中涉及的名字对应的是fruit那么就需要去FruitController与之对应 -->
    <bean id="fruit" class="com.atguigu.fruit.controllers.FruitController">
        <property name="fruitServiceimpl" ref="fruitServiceimpl"></property>
    </bean>
</beans>
        <!--
        1.概念
        HTML 超文本标记语言
        XML 可扩展的标记语言
        HTML 是XML的一个自集

        2.XML包含三个部分
        (1)XML声明,而且声明这一行代码必须在XML文件的第一行
        (2)DTD文档类型定义
        (3)XML正文
        -->

总结

今日内容:

  1. 再次学习Servlet的初始化方法
  1. Servlet生命周期:实例化、初始化、服务、销毁
  2. Servlet中的初始化方法有两个:init() , init(config)
    其中带参数的方法代码如下:
   public void init(ServletConfig config) throws ServletException {
     this.config = config ;
     init();
   }

另外一个无参的init方法如下:

   public void init() throws ServletException{
   }

如果我们想要在Servlet初始化时做一些准备工作,那么我们可以重写init方法
我们可以通过如下步骤去获取初始化设置的数据

  • 获取config对象:ServletConfig config = getServletConfig();
  • 获取初始化参数值: config.getInitParameter(key);
  1. 在web.xml文件中配置Servlet
 <servlet>
        <servlet-name>Demo01Servlet</servlet-name>
        <servlet-class>com.atguigu.servlet.Demo01Servlet</servlet-class>
        <init-param>
            <param-name>hello</param-name>
            <param-value>world</param-value>
        </init-param>
        <init-param>
            <param-name>uname</param-name>
            <param-value>jim</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Demo01Servlet</servlet-name>
        <url-pattern>/demo01</url-pattern>
    </servlet-mapping>
  1. 也可以通过注解的方式进行配置:
 @WebServlet(urlPatterns = {"/demo01"} ,
     initParams = {
         @WebInitParam(name="hello",value="world"),
         @WebInitParam(name="uname",value="jim")
     })
  1. 学习Servlet中的ServletContext和
    1. 获取ServletContext,有很多方法
      在初始化方法中: ServletContxt servletContext = getServletContext();
      在服务方法中也可以通过request对象获取,也可以通过session获取:
   request.getServletContext(); session.getServletContext()
2) 获取初始化值:
   servletContext.getInitParameter();
  1. 什么是业务层
    1. Model1和Model2
      MVC : Model(模型)、View(视图)、Controller(控制器)
      视图层:用于做数据展示以及和用户交互的一个界面
      控制层:能够接受客户端的请求,具体的业务功能还是需要借助于模型组件来完成
      模型层:模型分为很多种:有比较简单的pojo/vo(value object),有业务模型组件,有数据访问层组件

      1. pojo/vo : 值对象
      2. DAO : 数据访问对象
      3. BO : 业务对象
    2. 区分业务对象和数据访问对象:
      1) DAO中的方法都是单精度方法或者称之为细粒度方法。什么叫单精度?一个方法只考虑一个操作,比如添加,那就是insert操作、查询那就是select操作…
      2) BO中的方法属于业务方法,也实际的业务是比较复杂的,因此业务方法的粒度是比较粗的
      注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。
      那么这个业务方法中包含了多个DAO方法。也就是说注册这个业务功能需要通过多个DAO方法的组合调用,从而完成注册功能的开发。
      注册:
      1. 检查用户名是否已经被注册 - DAO中的select操作
      2. 向用户表新增一条新用户记录 - DAO中的insert操作
      3. 向用户积分表新增一条记录(新用户默认初始化积分100分) - DAO中的insert操作
      4. 向系统消息表新增一条记录(某某某新用户注册了,需要根据通讯录信息向他的联系人推送消息) - DAO中的insert操作
      5. 向系统日志表新增一条记录(某用户在某IP在某年某月某日某时某分某秒某毫秒注册) - DAO中的insert操作
      6. …

    3. 在库存系统中添加业务层组件

4.IOC
1) 耦合/依赖
依赖指的是某某某离不开某某某
在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。
我们系统架构或者是设计的一个原则是: 高内聚低耦合。
层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况0耦合(就是没有耦合)
2) IOC - 控制反转 / DI - 依赖注入
IOC - 控制反转 / DI - 依赖注入
控制反转:
1) 之前在Servlet中,我们创建service对象 , FruitService fruitService = new FruitServiceImpl();
这句话如果出现在servlet中的某个方法内部,那么这个fruitService的作用域(生命周期)应该就是这个方法级别;
如果这句话出现在servlet的类中,也就是说fruitService是一个成员变量,那么这个fruitService的作用域(生命周期)应该就是这个servlet实例级别
2) 之后我们在applicationContext.xml中定义了这个fruitService。然后通过解析XML,产生fruitService实例,存放在beanMap中,这个beanMap在一个BeanFactory中
因此,我们转移(改变)了之前的service实例、dao实例等等他们的生命周期。控制权从程序员转移到BeanFactory。这个现象我们称之为控制反转

依赖注入:
1) 之前我们在控制层出现代码:FruitService fruitService = new FruitServiceImpl();
那么,控制层和service层存在耦合。
2) 之后,我们将代码修改成FruitService fruitService = null ;
然后,在配置文件中配置:

   <bean id="fruit" class="FruitController">
        <property name="fruitService" ref="fruitService"/>
   </bean>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心向阳光的天域

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值