谈一谈我对三层架构和MVC模式的理解

文章目录

  • 初识MVC模式和三层架构
    • 前言
      • 前置知识
      • 什么是MVC模式?
      • 什么是三层架构?
      • MVC和三层架构的关系
      • 案例:
        • 前期准备:
        • 正式开始:
        • 效果演示:
        • 案例分析:

初识MVC模式和三层架构

前言

本文主要是博主对于这两者之间的个人认知,由于博主的认知能力有限,很可能存在纰漏,所以如有表述不当,或理解有误,恳请大家及时指出\~ o( ̄▽ ̄)ブ,让我们一起加油(ง •_•)ง,共同进步吧

前置知识

首先我们需要了解什么是设计模式、框架、架构模式、架构。这些知识,更加有利于我们对MVC模式和三层架构的理解(●’◡’●)

  • 设计模式(Design pattern),又称软件设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。本质就是对某一问题的一套最优解决方案

    主要作用提高代码的复用性

  • 框架(Framework)是构成一类特定软件可复用设计的一组相互协作的类。本质是半本成品软件

    主要作用提高开发效率

  • 架构模式,也叫架构风格,用于描述软件系统里的基本的结构组织或纲要。本质是一种具有指导意义的思想

    主要作用规范软件的开发

  • 架构,又称软件架构(software architecture),是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。本质是软件或系统的设计大纲

    主要作用提高软件的稳定性、可维护性和安全性

它们之间的联系

设计模式是一种针对某个具体的问题而做出的解决方案,而框架的主要目的是为了实现代码的重用,在实现期间很可能使用到多种设计模式;架构模式是一种指导思想,根据这种指导思想工程师可以创造出基于这种思想的多种框架;而架构是一个项目的大纲,这个大纲用于软件的设计,在设计这个软件期间可以会用到多种架构模式。

举个简略的例子加以印证:当我们在设计一款软件时,必须先由架构师做好架构,规划好软件的整体结构;然后确定需要使用哪些架构模式,比如要解决软件系统的数据与显示分离的问题,那就使用MVC模式……;最后交由下面的程序员进行开发,程序员开发过程中可能会使用多种框架,比如Spring、SpringMVC、MyBatis……;同时这些框架的实现很可能使用了多种设计模式,比如MyBatis就使用了单例模式、工厂模式、代理模式……

它们之间可以理解是一个层层包含关系,如图所示:

架构
架构模式
框架
设计模式

什么是MVC模式?

MVC(Model View Controller)模式是一种架构模式,主要思想是M和V的分离,它要求软件开发时,需要进行将【业务的处理】和【视图显示】 的实现代码进行分离,然后使用控制器对他们进行调度。

  • MVC 是一种分层开发的模式,其中:

    • M(Model):业务模型,主要用来处理业务逻辑,负责对数据库进行CRUD的基本操作,然后由这些基本操作构成一套业务处理方法,比如:查询、删除、修改等功能
    • V(View):视图窗口,主要用来进行页面展示,负责接收来自控制器的数据,并将其响应到浏览器的网页上

    • C(Controller):控制器,主要用来调度M和V,根据用户请求来选择要调用哪个模型来处理业务,以及最终由哪个视图为用户做出应答

谈一谈我对三层架构和MVC模式的理解_第1张图片

控制器(serlvlet)用来接收浏览器发送过来的请求,控制器调用模型(JavaBean)来获取数据,比如从数据库查询数据;控制器获取到数据后再交由视图(JSP)进行数据展示

  • MVC的优点
    • 降低了系统的复杂度。该模式符合面对对象设计原则之一的单一职责原则(也称康威定律),能够有效降低系统复杂度
    • 提高了开发效率。每一层之间都分工明确,职责单一,有利于开发人员的分工协作
    • 有利于组件重用。能够随时更换某一层的代码,对其他层的影响很小

什么是三层架构?

三层架构是一种架构模式,主要思想是“高内聚,低耦合”思想,它将各个功能模块划分为表现层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构。

  • 三层架构是将我们的项目分成了三个层面,分别:
    • 表现层(UI,User Interface):主要用来展示数据。负责和浏览器打交道,接收、请求、封装来自浏览器的请求数据,同时调用业务逻辑层的方法,然后将来自业务逻辑层的数据进行封装,最后将封装的数据响应到网页上
    • 业务逻辑层(BLL,Bussiness Logic Level):主要用来处理业务逻辑。负责调用数据访问层的SQL语句,实现业务功能,比如注册、登录功能的实现,同时获取来并封装自数据访问层的数据
    • 数据访问层(DAL,Data Access Layer):主要用来进行数据访问。负责和数据库打交道,对数据库进行CRUD基本操作

谈一谈我对三层架构和MVC模式的理解_第2张图片

  • 三层架构的优点
    • 提高代码的复用性。因为每个模块都是遵循”高内聚,低耦合“的设计思想,很容易抽取出来进行复用
    • 实现各层的解耦。有利于项目的维护、更新
    • 安全性高。用户端只能通过业务逻辑层来调用数据访问层,减少了入口点,把很多危险的系统功能都屏蔽了

MVC和三层架构的关系

两者的区别

  • 从适用范围上看

    • 三层架构是一个分层式的软件体系架构设计,适用于许多的项目。
    • MVC模式是为了让前端和业务逻辑代码和数据分开,只适用在web项目中。
  • 从目的上看

    两者的主要目的都是为了解耦,从而提高项目的可维护性,扩展性。三层架构侧重的是项目整体的解耦,而MVC侧重的是前端页面和业务逻辑处理的一个解耦,较之而言,三层架构解耦更彻底。

  • 从层次上看

    • 三层架构是框架层面上的
    • 而MVC模式是设计模式层面上的

    一个软件肯定要先确定好框架,之后才有下一步的设计模式,所以三层架构的层次要高于MVC模式

其次:三层架构的分层具有上下关系,上层依赖于下层。但MVC作为表现模式是不存在上下关系的,而是相互协作关系。

两者的关系

虽然MVC和三层架构都是架构模式,本质上都是一种软件设计上的指导思想,但两者在抽象层面和适用范围上还有有很大的区别的。三层架构是方法论,只提供一种抽象的指导思想,告诉开发者设计软件需要进行分层开发;而MVC提供了一个相对具体的指导思想,告诉开发者如何进行分层。可以理解MVC是三层架构这个方法论中的一种方法,他们是包含关系。

谈一谈我对三层架构和MVC模式的理解_第3张图片


案例:

一般而言,我们都会将三层架构和MVC搭配使用,整体使用三层架构,对于表现层使用VC模式。

任务:利用三层架构+MVC模式实现对tb_brand表的增、删、改、查功能

备注:本案例已经开源到Gitee和Github,感兴趣的小伙伴可以参观:

  • 知识汲取者的Github仓库:✈️传送门
  • 知识汲取者的Gitee仓库:✈️传送门

前期准备:

创建Web项目
创建目录
导入依赖
连接数据库
创建表
编写MyBatis配置文件
编写实体类
  • Step1:使用Maven创建Web项目

    详细步骤请参考:一文教你快速上手Maven

  • Step2:创建项目所需的目录

    谈一谈我对三层架构和MVC模式的理解_第4张图片

    三层架构:

    • 数据访问层:mapper
    • 业务逻辑层:service、工具(pojo、utils)
    • 表现层:JSP、HTML、web

    MVC:

    • 模型:mapper、service、工具(pojo、utils)
    • 视图:JSP、HTML
    • 控制器:web
  • Step3:导入项目所需依赖

    项目除了下面依赖的Tomcat7插件外,还需要依赖MavenHelper、MyBatisX两款插件。

    其实这些插件也不是必须品,只是为了方便开发

    pom.xml:

    
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        
        
        <modelVersion>4.0.0modelVersion>
        
        <groupId>com.hhxygroupId>
        <artifactId>day9_brand-demoartifactId>
        <version>1.0-SNAPSHOTversion>
        
        <packaging>warpackaging>
        
        <properties>
            <maven.compiler.source>16maven.compiler.source>
            <maven.compiler.target>16maven.compiler.target>
        properties>
        
    
        
        <dependencies>
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>8.0.27version>
            dependency>
            
            <dependency>
                <groupId>org.mybatisgroupId>
                <artifactId>mybatisartifactId>
                <version>3.5.5version>
            dependency>
            
            <dependency>
                <groupId>javax.servletgroupId>
                <artifactId>javax.servlet-apiartifactId>
                <version>3.1.0version>
                <scope>providedscope>
            dependency>
            
            <dependency>
                <groupId>javax.servlet.jspgroupId>
                <artifactId>jsp-apiartifactId>
                <version>2.2version>
                
                <scope>providedscope>
            dependency>
            
            <dependency>
                <groupId>jstlgroupId>
                <artifactId>jstlartifactId>
                <version>1.2version>
            dependency>
            <dependency>
                <groupId>taglibsgroupId>
                <artifactId>standardartifactId>
                <version>1.1.2version>
            dependency>
        dependencies>
    
        
        <build>
            <plugins>
                
                <plugin>
                    <groupId>org.apache.tomcat.mavengroupId>
                    <artifactId>tomcat7-maven-pluginartifactId>
                    <version>2.2version>
                    <configuration>
                        <port>8080port>
                        
                    configuration>
                plugin>
            plugins>
        build>
        
        
    project>
    
  • Step4:使用IDEA连接数据库servlet(没有可以创建一个)

    详细步骤请参考:手把手教你快速入门MyBatis从此解放你的双手

  • Step5:在IDEA中建立一张tb_brand表

    tb_brand:

    -- 删除tb_brand表
    drop table if exists tb_brand;
    -- 创建tb_brand表
    create table tb_brand
    (
        -- id 主键
        id           int primary key auto_increment,
        -- 品牌名称
        brand_name   varchar(20),
        -- 企业名称
        company_name varchar(20),
        -- 排序字段
        ordered      int,
        -- 描述信息
        description  varchar(100),
        -- 状态:0:禁用  1:启用
        status       int
    );
    -- 添加数据
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
           ('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1);
    
    
    SELECT * FROM tb_brand;
    

    这一步既可以在IDEA中进行,又可以在Navicat中进行(推荐在IDEA中进行)

  • Step6:编写MyBatis配置文件

    1)MyBatis核心配置文件:

    mybatis-config.xml:

    
    DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        
        <typeAliases>
            <package name="com.hhxy.pojo"/>
        typeAliases>
        
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///servlet?useSSL=false&characterEncoding=utf8&useServerPrepStmts=true"/>
                    <property name="username" value="root"/>
                    <property name="password" value="32345678"/>
                dataSource>
            environment>
        environments>
        
        <mappers>
            
            
            <package name="com.hhxy.mapper"/>
        mappers>
    
    configuration>
    

    2)SQL映射文件

    BrandMapper.xml:

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.hhxy.mapper.BrandMapper">
        
        <resultMap id="brandResultMap" type="Brand">
            <result column="brand_name" property="brandName">result>
            <result column="company_name" property="companyName">result>
        resultMap>
        
        
        <update id="update">
            update tb_brand
            <set>
                <if test="brandName!=null and brandName!=''">
                    brand_name = #{brandName},
                if>
                <if test="companyName!=null and companyName!=''">
                    company_name = #{companyName},
                if>
                <if test="ordered!=null and ordered!=''">
                    ordered = #{ordered},
                if>
                <if test="description!=null and description!=''">
                    description = #{description},
                if>
                <if test="status != null">
                    status = #{status}
                if>
            set>
            where id = #{id};
        update>
        
        <delete id="deleteById">
            delete from tb_brand where id=#{id};
        delete>
    mapper>
    
  • Step7:编写pojo实体类

    Brand:

    package com.hhxy.pojo;
    /**
     * 数据访问层(DAL)& 业务模型(Model)
     * 数据访问层:
     */
    public class Brand {
        // id 主键
        private Integer id;
        // 品牌名称
        private String brandName;
        // 企业名称
        private String companyName;
        // 排序字段
        private Integer ordered;
        // 描述信息
        private String description;
        // 状态:0:禁用  1:启用
        private Integer status;
    
    
        public Brand() {
        }
    
        public Brand(Integer id, String brandName, String companyName, String description) {
            this.id = id;
            this.brandName = brandName;
            this.companyName = companyName;
            this.description = description;
        }
    
        public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {
            this.id = id;
            this.brandName = brandName;
            this.companyName = companyName;
            this.ordered = ordered;
            this.description = description;
            this.status = status;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getBrandName() {
            return brandName;
        }
    
        public void setBrandName(String brandName) {
            this.brandName = brandName;
        }
    
        public String getCompanyName() {
            return companyName;
        }
    
        public void setCompanyName(String companyName) {
            this.companyName = companyName;
        }
    
        public Integer getOrdered() {
            return ordered;
        }
    
        public void setOrdered(Integer ordered) {
            this.ordered = ordered;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        public Integer getStatus() {
            return status;
        }
    
        public void setStatus(Integer status) {
            this.status = status;
        }
    
        @Override
        public String toString() {
            return "Brand{" +
                    "id=" + id +
                    ", brandName='" + brandName + '\'' +
                    ", companyName='" + companyName + '\'' +
                    ", ordered=" + ordered +
                    ", description='" + description + '\'' +
                    ", status=" + status +
                    '}';
        }
    }
    

正式开始:

这里可以顺序不固定,可以根据个人习惯而言。我比较习惯自下而上从数据访问层到表现层来编写(前提要先明确功能和业务逻辑)实际工作中,推荐自上而下去编写,这样当我们需要什么时就可以加什么

编写Mapper接口
编写SQL映射文件
编写Service类
编写Servlet类
编写html
编写jsp
编写web.xml
编写工具类
  • Step1:编写Mapper接口

    BrandMapper:

    package com.hhxy.mapper;
    
    import com.hhxy.pojo.Brand;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.ResultMap;
    import org.apache.ibatis.annotations.Select;
    
    import java.util.List;
    /**
     * 数据访问层(DAL)& 业务模型(Model)
     * 数据访问层:对数据库的CRUD
     * 业务模型:既要进行CRUD,又要进行逻辑功能的实现
     *           这里是业务模型的一部分,对数据库进行CRUD的基本操作
     */
    public interface BrandMapper {
        /*查询所有功能*/
        @Select("select * from tb_brand")
        @ResultMap("brandResultMap")
        List<Brand> selectAll();
    
        /*添加功能*/
        @Insert("insert into tb_brand(brand_name,company_name,ordered,description,status) " +
                "values(#{brandName},#{companyName},#{ordered},#{description},#{status})")
        void add(Brand brand);
    
        /*修改功能*/
        //更具id查询数据
        @Select("select * from tb_brand where id=#{id}")
        @ResultMap("brandResultMap")
        Brand selectById(int id);
        //根据id进行数据修改
        void update(Brand brand);
    
        /*删除功能*/
        void deleteById(int id);
    
    }
    
  • Step2:编写SQL映射文件

    BrandMapper.xml:

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.hhxy.mapper.BrandMapper">
        
        <resultMap id="brandResultMap" type="Brand">
            <result column="brand_name" property="brandName">result>
            <result column="company_name" property="companyName">result>
        resultMap>
        
        
        <update id="update">
            update tb_brand
            <set>
                <if test="brandName!=null and brandName!=''">
                    brand_name = #{brandName},
                if>
                <if test="companyName!=null and companyName!=''">
                    company_name = #{companyName},
                if>
                <if test="ordered!=null and ordered!=''">
                    ordered = #{ordered},
                if>
                <if test="description!=null and description!=''">
                    description = #{description},
                if>
                <if test="status != null">
                    status = #{status}
                if>
            set>
            where id = #{id};
        update>
        
        <delete id="deleteById">
            delete from tb_brand where id=#{id};
        delete>
    
    mapper>
    
  • Step3:编写工具类

    SqlSessionFactoryUtils:

    package com.hhxy.utils;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * 获取工厂对象的工具类
     * 利用了设计模式中的单例模式,单例模式中的饿汉单例模式
     */
    
    public class SqlSessionFactoryUtils {
        //1、定义成员变量,用于获取局部变量的值
        private static SqlSessionFactory sqlSF;
        //2、在静态代码块中获取SqlSessionFactory对象
        static{
            //2.1 定位MyBatis核心配置文件
            String resource = "./mybatis-config.xml";
            try {
                //2.2 加载MyBatis核心配置文件,获取输入流对象
                InputStream is = Resources.getResourceAsStream(resource);
                //2.3 获取SqlSessionFactory对象
                sqlSF = new SqlSessionFactoryBuilder().build(is);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * get方法,用于外部获取SqlSessionFactory对象
         * @return
         */
        public static SqlSessionFactory getSqlSF() {
            return sqlSF;
        }
    }
    
  • Step4:编写Service

    BrandService:

    package com.hhxy.service;
    
    import com.hhxy.mapper.BrandMapper;
    import com.hhxy.pojo.Brand;
    import com.hhxy.utils.SqlSessionFactoryUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    
    import java.util.List;
    
    /**
     * 业务逻辑层(BLL)& 业务模型(Model)
     * 业务逻辑层:调用数据访问层的基础功能,进行逻辑处理,实现业务功能
     * 业务模型:包括了业务逻辑层 和 数据访问层的所有功能
     *           这里是业务模型的一部分,进行逻辑处理,实现业务功能
     *
     */
    public class BrandService {
        //因为所有的方法都需要获取sqlSF对象,所以将其由局部变量变为成员,提升它的作用域
        SqlSessionFactory sqlSF = SqlSessionFactoryUtils.getSqlSF();
    
        /*查询所有功能*/
        /**
         * 查询所有数据
         * @return
         */
        public List<Brand> selectAll(){
            //1、使用工具类获取SqlSessionFactory对象
    
            //2、获取SqlSession对象
            SqlSession sqlS = sqlSF.openSession(true);
            //3、获取Mapper接口对象
            BrandMapper mapper = sqlS.getMapper(BrandMapper.class);
            //4、执行SQl语句
            List<Brand> brands = mapper.selectAll();
            //5、提交事物(已设置为自动提交)
            //6、释放资源
            sqlS.close();
            //7、返回查询结果
            return brands;
        }
    
        /*新增功能*/
        /**
         * 添加数据
         * @param brand
         */
        public void add(Brand brand){
            //1、使用工具类获取SqlSessionFactory对象
            //2、获取SqlSession对象
            SqlSession sqlS = sqlSF.openSession(true);
            //3、获取Mapper接口对象
            BrandMapper mapper = sqlS.getMapper(BrandMapper.class);
            //4、执行SQL语句
            mapper.add(brand);
            //5、提交事物(已设置为自动提交)
            //6、释放资源
            sqlS.close();
        }
    
        /*修改功能*/
        /**
         * 根据Id查询数据
         */
        public Brand selectById(int id){
            //1、使用工具类获取SqlSessionFactory对象
            //2、获取SqlSession对象
            SqlSession sqlS = sqlSF.openSession(true);
            //3、获取Mapper接口对象
            BrandMapper mapper = sqlS.getMapper(BrandMapper.class);
            //4、执行SQL语句
            Brand brand = mapper.selectById(id);
            //5、提交事物(已自动提交)
            //6、释放资源
            sqlS.close();
            //7、返回查询结果
            return brand;
        }
        /**
         * 更新数据
         */
        public void update(Brand brand){
            //1、使用工具类获取SqlSessionFactory对象
            //2、获取SqlSession对象
            SqlSession sqlS = sqlSF.openSession(true);
            //3、获取Mapper接口对象
            BrandMapper mapper = sqlS.getMapper(BrandMapper.class);
            //4、执行SQL语句
            mapper.update(brand);
            //5、提交事物(已手动提交)
            //6、释放资源
            sqlS.close();
        }
    
        /*删除功能*/
        /**
         * 更具id删除数据
         */
        public void delete(int id){
            //1、使用工具类获取SQL Session Factory对象
            //2、获取SqlSession对象
            SqlSession sqlS = sqlSF.openSession(true);
            //3、获取Mapper接口对象
            BrandMapper mapper = sqlS.getMapper(BrandMapper.class);
            //4、执行SQl语句
            mapper.deleteById(id);
            //5、提交事务(已手动提交)
            //6、释放资源
            sqlS.close();
        }
    
    }
    
  • Step5:编写Servlet

    1)SelectAllServlet:

    package com.hhxy.web;
    
    import com.hhxy.pojo.Brand;
    import com.hhxy.service.BrandService;
    
    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 java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 结构划分:表现层(UI)& 控制器( Controller)
     * 表现层:包括了控制器 和 视图的功能
     *         这里是表现层的一部分,调用业务逻辑层(Service)的功能获取数据并转发数据(然后展示数据)
     * 控制器:调用业务模型(Model)的功能获取数据并转发数据(展示数据交给视图)
     */
    @WebServlet("/SelectAllServlet")
    public class SelectAllServlet extends HttpServlet {
        //细节:因为在该类中要多次使用BrandService对象所以提升作用域
        BrandService service = new BrandService();
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("doPost方法被调用了");
    
            this.doGet(request, response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("doGet方法被调用了");
            /*查询所有*/
            //1、获取BrandService对象
            //2、调用BrandService对象完成查询
            List<Brand> brands = service.selectAll();
            //3、将数据存入Request域对象中
            request.setAttribute("brands",brands);
            //4、请求转发到brand.js,让其响应数据
            request.getRequestDispatcher("/jsp/brand.jsp").forward(request,response);
        }
    }
    
    

    2)AddServlet:

    package com.hhxy.web;
    
    import com.hhxy.pojo.Brand;
    import com.hhxy.service.BrandService;
    
    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 java.io.IOException;
    import java.nio.charset.StandardCharsets;
    
    @WebServlet("/AddServlet")
    public class AddServlet extends HttpServlet {
        //细节:因为在该类中要多次使用BrandService对象所以提升作用域
        BrandService service = new BrandService();
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request, response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            request.setCharacterEncoding("utf-8");
            //1、获取BrandService对象
            //2、接收请求参数(用户输入的数据)
            String brandName = request.getParameter("brandName");
            String companyName = request.getParameter("companyName");
            String ordered = request.getParameter("ordered");
            String description = request.getParameter("description");
            String status = request.getParameter("status");
    
            //3、解决中文乱码
            //方案一:Post方式:
            //request.setCharacterEncoding("utf-8");//这行代码要放在2、的前面
            /*
            //方案二:通用方式:
            //Step1:设置编码
            byte[] bytes1 = brandName.getBytes(StandardCharsets.ISO_8859_1);
            byte[] bytes2 = companyName.getBytes(StandardCharsets.ISO_8859_1);
            byte[] bytes3 = description.getBytes(StandardCharsets.ISO_8859_1);
            //Step2:设计解码
            brandName = new String(bytes1,StandardCharsets.UTF_8);
            companyName = new String(bytes2,StandardCharsets.UTF_8);
            description = new String(bytes3,StandardCharsets.UTF_8);
            */
    
            //4、封装数据
            Brand brand = new Brand();
            brand.setBrandName(brandName);
            brand.setCompanyName(companyName);
            brand.setOrdered(Integer.parseInt(ordered));
            brand.setDescription(description);
            brand.setStatus(Integer.parseInt(status));
            //5、调用addService对象完成添加
            service.add(brand);
            //6、请求转发到brand.js,查看添加后的结果
            request.getRequestDispatcher("/SelectAllServlet").forward(request,response);
    
        }
    }
    
    

    3)SelectByIdServlet:

    package com.hhxy.web;
    
    import com.hhxy.pojo.Brand;
    import com.hhxy.service.BrandService;
    
    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 java.io.IOException;
    
    @WebServlet("/SelectByIdServlet")
    public class SelectByIdServlet extends HttpServlet {
        //细节:因为在该类中要多次使用BrandService对象所以提升作用域
        BrandService service = new BrandService();
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request, response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            /*回显数据*/
            //1、获取BrandService对象
            //2、接收请求参数
            String id = request.getParameter("id");
            //3、BrandService对象完成完成查询
            Brand brand = service.selectById(Integer.parseInt(id));
            //4、将数据存储到Request域中
            request.setAttribute("brand",brand);
            //5、请求转发到updateBrand.jsp中,让其响应数据
            request.getRequestDispatcher("/jsp/updateBrand.jsp").forward(request,response);
        }
    }
    
    

    4)UpdateServlet:

    package com.hhxy.web;
    
    import com.hhxy.pojo.Brand;
    import com.hhxy.service.BrandService;
    
    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 java.io.IOException;
    import java.nio.charset.StandardCharsets;
    
    @WebServlet("/UpdateServlet")
    public class UpdateServlet extends HttpServlet {
        //细节:因为在该类中要多次使用BrandService对象,所以将其作用域提升
        BrandService service = new BrandService();
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request, response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //        request.setCharacterEncoding("utf-8");
            //1、获取Service对象
            //2、接收请求参数
            String id = request.getParameter("id");
            String brandName = request.getParameter("brandName");
            String companyName = request.getParameter("companyName");
            String ordered = request.getParameter("ordered");
            String description = request.getParameter("description");
            String status = request.getParameter("status");
    
            //3、解决中文乱码
            //方案一:Post方式
            //request.setCharacterEncoding("utf-8");//这行代码一定要放在获取请求参数之前!!!
            //方案二:通用方式:
            //Step1:设置编码
            byte[] bytes1 = brandName.getBytes(StandardCharsets.ISO_8859_1);
            byte[] bytes2 = companyName.getBytes(StandardCharsets.ISO_8859_1);
            byte[] bytes3 = description.getBytes(StandardCharsets.ISO_8859_1);
            //Step2:设计解码
            brandName = new String(bytes1,StandardCharsets.UTF_8);
            companyName = new String(bytes2,StandardCharsets.UTF_8);
            description = new String(bytes3,StandardCharsets.UTF_8);
    
            //4、封装数据
            Brand brand = new Brand();
            brand.setId(Integer.parseInt(id));
            brand.setBrandName(brandName);
            brand.setCompanyName(companyName);
            brand.setOrdered(Integer.parseInt(ordered));
            brand.setDescription(description);
            brand.setStatus(Integer.parseInt(status));
    
            //5、调用Service对象完成更新
            service.update(brand);
    
            //6、请求转发到brand.js,查看更新后的结果
            request.getRequestDispatcher("/SelectAllServlet").forward(request,response);
    
        }
    }
    

    5)DeleteServlet:

    package com.hhxy.web;
    
    import com.hhxy.pojo.Brand;
    import com.hhxy.service.BrandService;
    
    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 java.io.IOException;
    
    @WebServlet("/DeleteServlet")
    public class DeleteServlet extends HttpServlet {
        //细节:因为在该类中要多次使用BrandService对象所以提升作用域
        BrandService service = new BrandService();
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doGet(request, response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1、获取BrandService对象
            //2、接收请求参数
            String id = request.getParameter("id");
            //3、BrandService对象完成完成查询
            service.delete(Integer.parseInt(id));
            //4、请求转发到updateBrand.jsp中,让其响应数据
            request.getRequestDispatcher("/SelectAllServlet").forward(request,response);
        }
    }
    
  • Step6:编写HTML

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    <a href="http://localhost:8080/day9_brand-demo/SelectAllServlet">点击查看a>
    body>
    html>
    
  • Step7:编写JSP

    1)brand.jsp:

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%--
        结构划分:表现层(UI)& 视图(View)
        表现层:包括了视图 和 控制器的功能
                这里是表现层的一部分,用于展示数据
         视图:展示数据
    --%>
    
    
        
        展示所有数据
    
    
    

    <%--========================核心代码============================--%> <%--==========================================================--%>
    序号 品牌名称 企业名称 排序 品牌介绍 状态 操作
    ${brand.id} ${brand.brandName} ${brand.companyName} ${brand.ordered} ${brand.description} ${brand.status == 1 ? "启用":"禁用"} 修改 删除
    <%--增加点击事件--%>

    2)addBrand.jsp:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
    
    
        
        添加数据
    
    
    

    添加品牌

    品牌名称:
    企业名称:
    排序:
    描述信息:
    状态: 禁用 启用

    3)updateBrand.jsp:

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%--<%@page isELIgnored="false" %>--%>
    
        
        修改数据
    
    
    

    添加品牌

    <%--隐藏域,提交id,让UpdateServlet确定更新数据时的id--%> 品牌名称:
    企业名称:
    排序:
    描述信息:
    状态: 禁用 启用
    禁用 启用
  • Step8:编写web.xml

    
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
        
        <welcome-file-list>
            <welcome-file>html/index.htmlwelcome-file>
        welcome-file-list>
    web-app>
    

效果演示:

谈一谈我对三层架构和MVC模式的理解_第5张图片

谈一谈我对三层架构和MVC模式的理解_第6张图片

谈一谈我对三层架构和MVC模式的理解_第7张图片

谈一谈我对三层架构和MVC模式的理解_第8张图片

案例分析:

由于这些代码,业务逻辑大致都差不多,所以这里就拿相比之下较难的修改功能的实现逻辑来进行分析。

谈一谈我对三层架构和MVC模式的理解_第9张图片

遇到过的问题:

  • 不熟练的地方:

    • 忘记导入Servlet依赖和JSP依赖没有加provided

    • 忘记设置打包方式war

    • 忘记将依赖导全,导致500

  • 粗心的地方:

    • 依赖导错,导致500
    • 跳转路径配置错误,导致404
    • req.setCharacterEncoding("UTF-8");代码放在获取请求参数后面,导致乱码
  • 值得注意的地方:

    • 重定向需要加虚拟目录的,请求转发不需虚拟目录,其中html页面跳转要写全url
    • 请求数据中文乱码(这个打算单独写一篇文章总结以下我遇到过的乱码问题)
    • 用户输入的限制交给前端干,我们不需要去管接收的数据是否会不合理(所以测试要使用正确数据)

还有很多小错误,就不一 一列举了,主要原因还是不熟练……


PS:

现在对这两个东西有了一点大致的认知了,这东西还得实践才能更好地理解,看终究是难以理解的(纸上得来终觉浅,绝知此事要躬行),真正的理解还得靠后期逐渐的学习啊,如果觉得本文对你有所帮助,欢迎点赞+评论✍加油!少年,路还长


参考文章

  • 【J2EE】:MVC是框架?是设计模式?是架构?还是……_
  • mvc是一种设计模式吗?
  • MVC模式介绍
  • 架构和框架的区别
  • 【架构风格 架构模式 设计模式 概念】
  • 10种常用的软件架构模式

你可能感兴趣的:(#,Java,Backend,development,mvc,架构,java)