小白新手web开发简单总结(四)-web应用开发中的MVC

 

目录

一 与Android/iOS开发对比

二 web应用开发中的JSP

三 web应用开发中的一个简单的MVC

三 几个概念的区分

四 总结

五 回顾前面的几个问题 

1.Servlet、Filter、Listener的新的认知

2.context-param和ContextLoaderListener的新的认知

(1)ServletContext

(2)ApplicationContext

(3)WebApplicationContext

(4)三者之间关系

(5)Spring中的两种容器


一 与Android/iOS开发对比

小白新手web开发简单总结(三)-一个简单的Web开发项目中简单的创建了一个web应用,因为之前做APP开发,所以希望拿着自己熟悉的东西来对比学习这个web应用开发。所以对比Android/iOS应用开发,发现都有一些相同的地方:

  • 1.从发布上线角度,三者都需要打包,然后放到对应的运行环境中运行,只不过差别在于:

 

  • 2.从开发流程角度,三者都需要有页面渲染->业务逻辑->网络通信->数据存储过程,只不过差别在于:

当然这个开发流程总结的比较宽泛,是基于目前初学者总结的,后面随着自己对web应用开发的深入,在返回来看自己的这个总结是否合理。另外在业务逻辑和数据存储这两部分应该还是比较负责的一些东西,学习自己在深入去学习。

二 web应用开发中的JSP

我们在小白新手web开发简单总结(三)-一个简单的Web开发项目中的FirstServlet中会往HttpServletResponse的writer中写入一段Html代码,如下:

    writer.write(String.format("<h1> Hello Web %s ,This is a simple web!</h1>",count));

如果我们简单的输出这么一句话,我们通过这种方式写入是没有问题的,但想想在实际开发一个网站的时候,任何一个页面都会有比这复杂很多的UI、UI状态以及UI逻辑,那么如果在单纯的靠这种方式写入,基本上在实现上是不可能的。所以就有了JSP(Java Server Page)。

JSP是一种动态网页技术,在项目中文件以.jsp结尾,这些文件必须放置到项目的webapp/目录下,最终打包成war包,然后部署到服务器。可以响应浏览器发送过来到请求,并根据请求的内容动态生成Html、xml或者其他格式的web网页,最后返回给浏览器。其实JSP文件在执行之前被编译成Java代码写的Servlet(在Tomcat的临时目录下就可以找到对应的xxx_jsp.java),所以说一个JSP就是对应这一个Servlet。

当项目打包上线之后,可以通过http://localhost:8080/xxx.jsp或http://localhost:8080/Servlet的url路径(在Servlet中转发到该xxx.jsp)两种方式来访问。

现在先通过一个简单的示例来了解下这个JSP:

(1)编写second.jsp的相关代码

<%-- 用来解决中文在浏览器乱码的问题 --%>
<%@page language="java" import="java.util.*" contentType="text/html; charset=GB2312"  %>
<html>
    <head>
        <title>First JSP</title>
    </head>

    <body>
    <%-- 这是一个JSP注释示例方式 --%>
        <h1> 这是通过 JSP 渲染的页面</h1>
        <p>
    <%-- 这是一个添加Java代码示例方式 --%>
            <%
                out.println("这是通过java输出的文字,获取url中的key为");

             %>
        <%-- 行内元素标签 --%>
            <span style="color:yellowgreen">
                <%= request.getParameter("key")%>
            </span>
        </p>
         <p>
             <%-- 方法和变量的声明 --%>
             <%! int count = 1;%>
            <%
                out.println(String.format("初始化的count的值为%d",count));
            %>
        </p>
        <p>
            <%!
                int getCount(){
                    return count;
                }
            %>
        </p>
    </body>
</html>

从代码中可以看到 一个JSP实际上是一个Html页面,里面可以动态修改Html页面的一些内容。具体的JSP语法等以后在研究。一个JSP一般要包括四部分元素,见小白新手web开发简单总结(五)-JSP页面的四元素

现在还是参照在小白新手web开发简单总结(三)-一个简单的Web开发项目提到的方法来允许web应用项目,其实现在就可以通过http://localhost:8080/second.jsp?key=感冒药来访问该jsp了,显示界面如下:

这样我们通过一个JSP来实现了一个Servlet,另外我们看下Tomcat临时目录下可以看到有一个对应的second_jsp.java的java文件。

从源码中不难发现在下面的方法来完成了之前我们在写FirstServlet.java的逻辑,将最终的HTML写入到HttpServletResponse返回给浏览器。

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
    throws java.io.IOException, javax.servlet.ServletException {

}

所以JSP就是对应一个Servlet,会自动将.jsp文件编译成.java文件。与Servlet的区别就在于JSP就是在HTML中嵌入动态输出文件,而Servlet是在Java代码中输出HTML。

平时我们在访问一个网站的时候,很少会看到通过http://localhost:8080/second.jsp这种url方式,所以我们还需要将second.jsp映射到一个url上,当然基于之前的简单web应用实例来说,可以通过在写一个SeondSerlvet.java方式来将second.jsp映射成一个url(我理解的这也就是Spring项目中的将Controller映射到.jsp的一个逻辑了)。

(2)增加SecondServlet.java将second.jsp映射成一个url


@WebServlet(urlPatterns = "/second")
public class SecondServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("/second.jsp").forward(req, resp);
    }
}

启动项目之后,就可以通过http://localhost:8080/second?key=成功来直接访问到servlet.jsp这个页面了。相关的代码都已经上传到githut,地址为:https://github.com/wenjing-bonnie/build-spring.git

三 web应用开发中的一个简单的MVC

MVC:Model-View-Controller。Model主要指的是一些业务模型,View就是用户能看到的界面,Controller就是初始化View和Model,通过Model来获取渲染View的数据,将Model与View的代码分离,那么在一个web应用开发中这三层是怎么体现出来的呢?

通过前面几次的简单例子,也可以对比出:使用Servlet和JSP都是用来写业务逻辑的:

但是Servlet适合编写Java代码,处理复杂的业务逻辑,但是对于不利于输出复杂的HTML;而JSP适合编写HTML,并且可以动态插入内容,但不适合复杂的Java代码。那么我们其实就可以将复杂的业务逻辑交给Java代码,而将最后显示的结果交给JSP。

用一个简单的例子来看下这两个是怎么配合使用:模拟一个用户在某购物网站上的购物车展示图书名字和价格(在实际开发中比下面的逻辑更加复杂,仅仅做模拟)。

  • 1.分别定义图书和用户的实体类(在实际开发中这应该就是对应数据库的一张表)
public class Book {
    public String name;
    public float price;
}

public class Customer {
    public long memberId;
    public String memberName;
}
  •  2.定义BookController实现根据图书名查出图书的价格
public class BookController {

    private SqlDataBase sqlDataBase;

    /**
     * 根据用户购买的图片获取图书价格,当然在实际的处理要比这个复杂
     *
     * @param name
     * @return
     */
    public Book getBook(String name) {
        Book book = new Book();
        //模拟查询数据库
        sqlDataBase.query(name);
        book.name = name;
        book.price = 39;
        return book;
    }
}
  • 3.定义CustomerController类实现根据用户的id来查询到用户的名字
public class CustomerController {
    private SqlDataBase sqlDataBase;

    /**
     * 根据用户id获取用户的名字
     *
     * @param memberId
     * @return
     */
    public Customer getCustomer(long memberId) {
        Customer customer = new Customer();
        //模拟查询数据库
        sqlDataBase.query(memberId);
        customer.memberId = memberId;
        customer.memberName = "小刘";
        return customer;
    }
}
  • 4.在BuyServlet中获取用户的名字以及用户购买的图书价格,然后将最后的结果交给buy.jsp来处理

在BuyServlet中进行实例化BookController和CustomerController,然后获取到Book和Customer,然后交给buy.jsp来渲染页面。

@WebServlet(urlPatterns = "/buy")
public class BuyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //模拟从数据库中根据"name"找到对应的Book实体对象
        String name = req.getParameter("name");
        BookController bookController = new BookController();
        Book book = bookController.getBook(name);
        //模拟从数据库中得到Customer
        CustomerController customerController = new CustomerController();
        Customer customer = customerController.getCustomer(122);
        req.setAttribute("book", book);
        req.setAttribute("customer", customer);
        //交给jsp来动态渲染
        req.getRequestDispatcher("/buy.jsp").forward(req, resp);
    }
}

从 buy.jsp中我们可以看到,在这里面不需要关心Book和Customer是怎么获得的,只需要根据BuyServlet给到的model对象来渲染UI就可以了。

<%--
  Created by IntelliJ IDEA.
  User: j1
  Date: 2021/2/10
  Time: 11:04
  To change this template use File | Settings | File Templates.
--%>
<%@ page import="com.wj.mvc.Customer" contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.wj.mvc.Book" %>
<%
    Customer customer = (Customer) request.getAttribute("customer");
    Book book = (Book) request.getAttribute("book");
%>
<html>
<head>
    <title>Mall</title>
</head>
<body>

    <h1>模拟某网站购物</h1>
    <p>
        亲爱的 <span style="color:red;size: A3;"><%= customer.memberName%></span> 顾客
    </p>
    <p>
        购买的图书为:<span style="color: yellowgreen;size: A3">《<%= book.name%>》</span>
        ,需要付款 <span style="color: yellowgreen;size: A3"><%= book.price%></span> 元
    </p>

</body>
</html>

运行项目,在浏览器中输入http://localhost:8080/buy?name=HeadFirst设计模式看下结果:

从这个简单的例子可以看出,其实buy.jsp是一个View的展示,Book和Customer是Model对象,而BuyServlet在处理业务逻辑,拥有Model和View,负责获取Model,并将Model交给View来处理,并且结合了Servlet和JSP两者的优点,不管在处理业务逻辑或者页面渲染,显得比单独使用任何一方都显得更方便。

相关代码已经上传的github :https://github.com/wenjing-bonnie/build-spring.git  对应包com.wj.mvc下的相关代码。

三 几个概念的区分

其实在上面的例子中,其实还是不太灵活。每次在写一个页面的时候,都必须对应一个类,并且都需要继承HttpServlet。那么就有了后面的Spring MVC框架。

1.什么是Spring

Spring是一个容器框架。核心就是提供一个IoC(Invsersion of Control 控制反转)容器,可以管理JavaBean组件,维护组件之间的关系,包括组件的生命周期的管理、配置以及组装。

补充:容器可以理解为为某种特定组件运行提供必要的软件环境。例如Tomcat是Servlet容器,为运行Servlet提供环境;Docker为Linux进程容器,为运行特定的Lunix进程提供环境,所以Spring就是一个JavaBean组件容器。

像我们在第二部分提到的那个例子有下面几个弊端:

(1)在BuyServlet中使用每个Controller的时候,都需要知道怎么创建;

(2)如果Controller之间有依赖关系的话,里面的实例不能共用;

(3)上述的每个过程需要开发者进行控制。

而Spring正是解决这个问题,组件的创建不需要开发者创建,而是直接交给IoC容器,开发者只需要通过xml文件配置组件以及组件之间的依赖关系;并且像前面提到的第二个问题,也已经避免,只要在一个配置,如果两个类之间有依赖关系,那么在另外一个类中可以直接使用。IoC容器来负责管理组件的整个生命周期。

2.什么是Spring MVC

web层的MVC框架,替代了Servlet。通过DispatcherServlet来将请求交给不同的模块进行处理。可以看出Struts2(本质相当于一个Servlet)+Spring的整合。

3.什么是Spring Boot

微服务框架,简化Spring应用的创建、运行、调试和部署,可只专注Spring开发,而无需过多关注XML配置。

四 总结

因为之前是做移动开发,所以经过两周时间,终于可以对比移动开发的相关内容,了解到web应用的整个开发流程。所以后面要继续去研究一个Spring MVC工程的创建过程了:

  • 1.web应用开发最后被打包成war包,放到已经安装了Tomcat的服务器;
  • 2.Tomcat其实就war包的一个环境;
  • 3.所谓的项目上线成功,肯定最后要启动Tomcat服务器,那么就会读取war包的内容,然后在浏览器中输入网址,就可以打开对应的页面;
  • 4.Servlet可以用Java代码来专注业务逻辑;然后将Model传递到JSP,然后有JSP来渲染页面;
  • 5.Spring就是一个IoC容器,用来管理JavaBean组件的生命周期。

五 回顾前面的几个问题 

在回顾一下小白新手web开发简单总结(二)-什么是web.xml ,发现之前理解有些模糊的地方又有了一些新的认识:

1.Servlet、Filter、Listener的新的认知

这一篇是自己最初的认识web应用开发项目的时候,第一次接触的一个文件。当时没有怎么搞清楚为什么要配置这些内容。但是现在总结下来:一个web应用开发通常包括三部分内容:

  • (1)处理动态业务组件:Servlet、Filter、Listener

所以在web.xml文件中配置了一些Filter、Listener以及Servlet

  • (2)视图组件:如JSP

java代码来实现负责的业务逻辑,最后通过req.getRequestDispatcher("/buy.jsp").forward(req, resp);的方式来动态渲染页面,这个JSP有点类似微信小程序的.wxml文件

  • (3)静态资源文件:如CSS、JS等

通常一个web应用在部署生产环境的时候,会使用Nginx和Tomcat服务器配置使用。Nginx作为网关,充当反向代理和静态服务器,可高效的处理静态文件,只将动态请求交给Tomcat服务器(所以Tomcat服务器通常运行业务系统)。同时也可将Https、防火墙、限速、反爬虫等功能放到Nginx,让webapp更多的只是关注业务逻辑。

2.context-param和ContextLoaderListener的新的认知

(1)ServletContext

<context-param>配置的是ServletContext的参数,而ServletContext是Servlet上下文,Servlet容器会每个应用程序创建一个ServletContext对象,是全局唯一,为所有的Servlet共用这一个对象,用于Servlet之间传递数据。

(2)ApplicationContext

ContextLoaderListener是监听Tomcat在发布web应用的过程, 在这过程中自动装配ApplicationContext的配置信息。而这个ApplicationContext是Spring实现IoC的核心接口,通过该ApplicationContext可以获取到Spring的IoC容器,那么就可以获取到容器中所有的Java Bean的实例。在Spring允许存在多个ApplicationContext。

常见的ApplicationContext实现类有:

(1)ClassPathXmlApplicationContext:加载类路径下对应的配置文件

    ApplicationContext context = new ClassPathXmlApplicationContext("config/application-context.xml");

(2)FileSystemXmlApplicationContext:加载磁盘任意路径下的配置文件,必须有访问权限

    ApplicationContext ctx = new FileSystemXmlApplicationContext("/Users/wj/Documents/java/pc/build-spring/src/main/resources/config/application-context.xml")

没有盘符则是项目的工作路径,即项目的根目录;有盘符就是文件的绝对路径 

(3)WebApplicationContext:专门加载针对web应用的配置文件,通常有两种实现类:

  • 1)XmlWebApplicationContext:通过XML文件来读取配置的JavaBean;
  • 2)AnnotationConfigApplicationContext:通过读取@Configuration和@Bean对应的java类来读取配置的JavaBean

有了IoC容器之后,ApplicationContext可以通过两种方式来获取到Bean:

(1)通过JavaBean的类型,最常使用的方式

        ApplicationContext context = new ClassPathXmlApplicationContext("config/application-context.xml");
        RegisterService service = context.getBean(RegisterService.class);

(2) 通过JavaBean的ID

        ApplicationContext context = new ClassPathXmlApplicationContext("config/application-context.xml");
       // 该ID为在xml文件中配置的id;
        RegisterService service = (RegisterService)context.getBean("registerService");

(3)WebApplicationContext

web应用的上下文,是ApplicationContext的子接口。只是在ApplicationContext的基础上,增加了对ServletContext 的引用,可以在WebApplicationContext通过 getServletContext()来访问到ServletContext。

(4)三者之间关系

 综合ServletContext、ApplicationContext、WebApplicationContext三者之间的关系为:

(1)WebApplicationContext为ApplicationContext子接口,里面含有ServletContext;

(2)Tomcat在启动的时候,首先要创建一个ServletContext作为Servlet容器

(3)在监听Tomcat发布web应用的过程中,会创建一个WebApplicationContext(这个时候读取的就是contextConfigLocation中配置的xml文件),用来获取IoC容器中配置的各种JavaBean;

(4)在WebApplicationContext中包含了ServletContext,可以通过getServletContext()来访问到ServletContext;

(5)在ServletContext中也可以获取WebApplicationContext,因为已经将WebApplicationContext作为一个属性值放到ServletContext中,对应的key为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE

(5)Spring中的两种容器

另外Spring除去ApplicationContext这种IoC容器,还有BeanFactory这种容器。两者区别在于BeanFactory会按需创建Bean,只有在第一次获取Bean的时候才会创建Bean;而ApplicationContext会一次性创建所有的Bean。实际上ApplicationContext是从BeanFactory中继承而来的。

下一篇就去学习下Spring的IoC容器:小白新手web开发简单总结(六)-Spring的IoC容器

 

猜你喜欢

转载自blog.csdn.net/nihaomabmt/article/details/113767898