目录
一 与Android/iOS开发对比
二 web应用开发中的JSP
三 web应用开发中的一个简单的MVC
三 几个概念的区分
四 总结
五 回顾前面的几个问题
1.Servlet、Filter、Listener的新的认知
2.context-param和ContextLoaderListener的新的认知
(1)ServletContext
(2)ApplicationContext
(3)WebApplicationContext
(4)三者之间关系
(5)Spring中的两种容器
在小白新手web开发简单总结(三)-一个简单的Web开发项目中简单的创建了一个web应用,因为之前做APP开发,所以希望拿着自己熟悉的东西来对比学习这个web应用开发。所以对比Android/iOS应用开发,发现都有一些相同的地方:
当然这个开发流程总结的比较宽泛,是基于目前初学者总结的,后面随着自己对web应用开发的深入,在返回来看自己的这个总结是否合理。另外在业务逻辑和数据存储这两部分应该还是比较负责的一些东西,学习自己在深入去学习。
我们在小白新手web开发简单总结(三)-一个简单的Web开发项目中的FirstServlet中会往HttpServletResponse的writer中写入一段Html代码,如下:
writer.write(String.format(" Hello Web %s ,This is a simple web!
",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" %>
First JSP
<%-- 这是一个JSP注释示例方式 --%>
这是通过 JSP 渲染的页面
<%-- 这是一个添加Java代码示例方式 --%>
<%
out.println("这是通过java输出的文字,获取url中的key为");
%>
<%-- 行内元素标签 --%>
<%= request.getParameter("key")%>
<%-- 方法和变量的声明 --%>
<%! int count = 1;%>
<%
out.println(String.format("初始化的count的值为%d",count));
%>
<%!
int getCount(){
return count;
}
%>
从代码中可以看到 一个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
MVC:Model-View-Controller。Model主要指的是一些业务模型,View就是用户能看到的界面,Controller就是初始化View和Model,通过Model来获取渲染View的数据,将Model与View的代码分离,那么在一个web应用开发中这三层是怎么体现出来的呢?
通过前面几次的简单例子,也可以对比出:使用Servlet和JSP都是用来写业务逻辑的:
但是Servlet适合编写Java代码,处理复杂的业务逻辑,但是对于不利于输出复杂的HTML;而JSP适合编写HTML,并且可以动态插入内容,但不适合复杂的Java代码。那么我们其实就可以将复杂的业务逻辑交给Java代码,而将最后显示的结果交给JSP。
用一个简单的例子来看下这两个是怎么配合使用:模拟一个用户在某购物网站上的购物车展示图书名字和价格(在实际开发中比下面的逻辑更加复杂,仅仅做模拟)。
public class Book {
public String name;
public float price;
}
public class Customer {
public long memberId;
public String memberName;
}
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;
}
}
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;
}
}
在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");
%>
Mall
模拟某网站购物
亲爱的 <%= customer.memberName%> 顾客
购买的图书为:《<%= book.name%>》
,需要付款 <%= book.price%> 元
运行项目,在浏览器中输入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 ,发现之前理解有些模糊的地方又有了一些新的认识:
这一篇是自己最初的认识web应用开发项目的时候,第一次接触的一个文件。当时没有怎么搞清楚为什么要配置这些内容。但是现在总结下来:一个web应用开发通常包括三部分内容:
所以在web.xml文件中配置了一些Filter、Listener以及Servlet
java代码来实现负责的业务逻辑,最后通过req.getRequestDispatcher("/buy.jsp").forward(req, resp);的方式来动态渲染页面,这个JSP有点类似微信小程序的.wxml文件
通常一个web应用在部署生产环境的时候,会使用Nginx和Tomcat服务器配置使用。Nginx作为网关,充当反向代理和静态服务器,可高效的处理静态文件,只将动态请求交给Tomcat服务器(所以Tomcat服务器通常运行业务系统)。同时也可将Https、防火墙、限速、反爬虫等功能放到Nginx,让webapp更多的只是关注业务逻辑。
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应用的配置文件,通常有两种实现类:
有了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");
web应用的上下文,是ApplicationContext的子接口。只是在ApplicationContext的基础上,增加了对ServletContext 的引用,可以在WebApplicationContext通过 getServletContext()来访问到ServletContext。
综合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
另外Spring除去ApplicationContext这种IoC容器,还有BeanFactory这种容器。两者区别在于BeanFactory会按需创建Bean,只有在第一次获取Bean的时候才会创建Bean;而ApplicationContext会一次性创建所有的Bean。实际上ApplicationContext是从BeanFactory中继承而来的。
下一篇就去学习下Spring的IoC容器:小白新手web开发简单总结(六)-Spring的IoC容器