[java][基础]JSP

目标:

  • 理解 JSP 及 JSP 原理

  • 能在 JSP中使用 EL表达式JSTL标签

  • 理解 MVC模式三层架构

  • 能完成品牌数据的增删改查功能

1,JSP 概述

==JSP(全称:Java Server Pages):Java 服务端页面。==是一种动态的网页技术,其中既可以定义 HTML、JS、CSS等静态内容,还可以定义 Java代码的动态内容,也就是 JSP = HTML + Java。如下就是jsp代码

<html><head><title>Title</title></head><body><h1>JSP,Hello World</h1><%System.out.println("hello,jsp~");%></body>
</html>

上面代码 h1 标签内容是展示在页面上,而 Java 的输出语句是输出在 idea 的控制台。

那么,JSP 能做什么呢?现在我们只用 servlet 实现功能,看存在什么问题。如下图所示,当我们登陆成功后,需要在页面上展示用户名

上图的用户名是动态展示,也就是谁登陆就展示谁的用户名。只用 servlet 如何实现呢?在今天的资料里已经提供好了一个 LoginServlet ,该 servlet 就是实现这个功能的,现将资料中的 LoginServlet.java 拷贝到 request-demo 项目中来演示。接下来启动服务器并访问登陆页面

输入了 zhangsan 用户的登陆信息后点击 登陆 按钮,就能看到如下图效果

当然如果是 lisi 登陆的,在该页面展示的就是 lisi,欢迎您,动态的展示效果就实现了。那么 LoginServlet 到底是如何实现的,我们看看它里面的内容

上面的代码有大量使用到 writer 对象向页面写标签内容,这样我们的代码就显得很麻烦;将来如果展示的效果出现了问题,排错也显得有点力不从心。而 JSP 是如何解决这个问题的呢?在资料中也提供了一个 login.jsp 页面,该页面也能实现该功能,现将该页面拷贝到项目的 webapp下,需要修改 login.html 中表单数据提交的路径为下图

重新启动服务器并进行测试,发现也可以实现同样的功能。那么 login.jsp 又是如何实现的呢?那我们来看看 login.jsp 的代码

上面代码可以看到里面基本都是 HTML 标签,而动态数据使用 Java 代码进行展示;这样操作看起来要比用 servlet 实现要舒服很多。

JSP 作用:简化开发,避免了在Servlet中直接输出HTML标签。

2,JSP 快速入门

接下来我们做一个简单的快速入门代码。

2.1 搭建环境

创建一个maven的 web 项目,项目结构如下:

pom.xml 文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
​<groupId>org.example</groupId><artifactId>jsp-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging>
​<properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties>
​<dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency></dependencies>
​<build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin></plugins></build>
</project>

2.2 导入 JSP 依赖

dependencies 标签中导入 JSP 的依赖,如下

<dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope>
</dependency>

该依赖的 scope 必须设置为 provided,因为 tomcat 中有这个jar包了,所以在打包时我们是不希望将该依赖打进到我们工程的war包中。

2.3 创建 jsp 页面

在项目的 webapp 下创建jsp页面

通过上面方式创建一个名为 hello.jsp 的页面。

2.4 编写代码

hello.jsp 页面中书写 HTML 标签和 Java 代码,如下

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><h1>hello jsp</h1>
​<%System.out.println("hello,jsp~");%>
</body>
</html>

2.5 测试

启动服务器并在浏览器地址栏输入 http://localhost:8080/jsp-demo/hello.jsp,我们可以在页面上看到如下内容

同时也可以看到在 idea 的控制台看到输出的 hello,jsp~ 内容。

3,JSP 原理

我们之前说 JSP 就是一个页面,那么在 JSP 中写 html 标签,我们能理解,但是为什么还可以写 Java 代码呢?

因为 ==JSP 本质上就是一个 Servlet。==接下来我们聊聊访问jsp时的流程

  1. 浏览器第一次访问 hello.jsp 页面

  2. tomcat 会将 hello.jsp 转换为名为 hello_jsp.java 的一个 Servlet

  3. tomcat 再将转换的 servlet 编译成字节码文件 hello_jsp.class

  4. tomcat 会执行该字节码文件,向外提供服务

我们可以到项目所在磁盘目录下找 target\tomcat\work\Tomcat\localhost\jsp-demo\org\apache\jsp 目录,而这个目录下就能看到转换后的 servlet

打开 hello_jsp.java 文件,来查看里面的代码

由上面的类的继承关系可以看到继承了名为 HttpJspBase 这个类,那我们在看该类的继承关系。到资料中的找如下目录: 资料\tomcat源码\apache-tomcat-8.5.68-src\java\org\apache\jasper\runtime ,该目录下就有 HttpJspBase 类,查看该类的继承关系

可以看到该类继承了 HttpServlet ;那么 hello_jsp 这个类就间接的继承了 HttpServlet ,也就说明 hello_jsp 是一个 servlet

继续阅读 hello_jsp 类的代码,可以看到有一个名为 _jspService() 的方法,该方法就是每次访问 jsp 时自动执行的方法,和 servlet 中的 service 方法一样 。

而在 _jspService() 方法中可以看到往浏览器写标签的代码:

以前我们自己写 servlet 时,这部分代码是由我们自己来写,现在有了 jsp 后,由tomcat完成这部分功能。

4,JSP 脚本

JSP脚本用于在 JSP页面内定义 Java代码。在之前的入门案例中我们就在 JSP 页面定义的 Java 代码就是 JSP 脚本。

4.1 JSP 脚本分类

JSP 脚本有如下三个分类:

  • <%...%>:内容会直接放到_jspService()方法之中

  • <%=…%>:内容会放到out.print()中,作为out.print()的参数

  • <%!…%>:内容会放到_jspService()方法之外,被类直接包含

代码演示:

hello.jsp 中书写

<%System.out.println("hello,jsp~");int i = 3;
%>

通过浏览器访问 hello.jsp 后,查看转换的 hello_jsp.java 文件,i 变量定义在了 _jspService() 方法中

hello.jsp 中书写

<%="hello"%>
<%=i%>

通过浏览器访问 hello.jsp 后,查看转换的 hello_jsp.java 文件,该脚本的内容被放在了 out.print() 中,作为参数

hello.jsp 中书写

<%!void  show(){}String name = "zhangsan";
%>

通过浏览器访问 hello.jsp 后,查看转换的 hello_jsp.java 文件,该脚本的内容被放在了成员位置

4.2 案例

4.2.1 需求

使用JSP脚本展示品牌数据

说明:

  • 在该案例中数据不从数据库中查询,而是在 JSP 页面上写死

4.2.2 实现
  • 将资料 资料\1. JSP案例素材 中的 Brand.java 文件放置到项目的 com.itheima.pojo 包下

  • 在项目的 webapp 中创建 brand.jsp ,并将 brand.html页面中的内容拷贝过来。brand.jsp 内容如下

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><title>Title</title>
    </head>
    <body>
    <input type="button" value="新增"><br>
    <hr><table border="1" cellspacing="0" width="800"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th>
    ​</tr><tr align="center"><td>1</td><td>三只松鼠</td><td>三只松鼠</td><td>100</td><td>三只松鼠,好吃不上火</td><td>启用</td><td><a href="#">修改</a> <a href="#">删除</a></td></tr>
    ​<tr align="center"><td>2</td><td>优衣库</td><td>优衣库</td><td>10</td><td>优衣库,服适人生</td><td>禁用</td>
    ​<td><a href="#">修改</a> <a href="#">删除</a></td></tr>
    ​<tr align="center"><td>3</td><td>小米</td><td>小米科技有限公司</td><td>1000</td><td>为发烧而生</td><td>启用</td>
    ​<td><a href="#">修改</a> <a href="#">删除</a></td></tr></table>
    </body>
    </html>

    现在页面中的数据都是假数据。

  • brand.jsp 中准备一些数据

    <%// 查询数据库List<Brand> brands = new ArrayList<Brand>();brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0));brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1));
    %>

    ==注意:==这里的类是需要导包的

  • brand.jsp 页面中的 table 标签中的数据改为动态的

    <table border="1" cellspacing="0" width="800"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th>
    ​</tr><%for (int i = 0; i < brands.size(); i++) {//获取集合中的 每一个 Brand 对象Brand brand = brands.get(i);}%><tr align="center"><td>1</td><td>三只松鼠</td><td>三只松鼠</td><td>100</td><td>三只松鼠,好吃不上火</td><td>启用</td><td><a href="#">修改</a> <a href="#">删除</a></td></tr>
    </table>

    上面的for循环需要将 tr 标签包裹起来,这样才能实现循环的效果,代码改进为

    <table border="1" cellspacing="0" width="800"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th>
    ​</tr><%for (int i = 0; i < brands.size(); i++) {//获取集合中的 每一个 Brand 对象Brand brand = brands.get(i);%><tr align="center"><td>1</td><td>三只松鼠</td><td>三只松鼠</td><td>100</td><td>三只松鼠,好吃不上火</td><td>启用</td><td><a href="#">修改</a> <a href="#">删除</a></td></tr><%}%></table>

    注意:<%%> 里面写的是 Java 代码,而外边写的是 HTML 标签

    上面代码中的 td 标签中的数据都需要是动态的,所以还需要改进

    <table border="1" cellspacing="0" width="800"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th>
    ​</tr><%for (int i = 0; i < brands.size(); i++) {//获取集合中的 每一个 Brand 对象Brand brand = brands.get(i);%><tr align="center"><td><%=brand.getId()%></td><td><%=brand.getBrandName()%></td><td><%=brand.getCompanyName()%></td><td><%=brand.getOrdered()%></td><td><%=brand.getDescription()%></td><td><%=brand.getStatus() == 1 ? "启用":"禁用"%></td><td><a href="#">修改</a> <a href="#">删除</a></td></tr><%}%></table>
4.2.3 成品代码
<%@ page import="com.itheima.pojo.Brand" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
​
<%// 查询数据库List<Brand> brands = new ArrayList<Brand>();brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0));brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1));
​
%>
​
​
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<input type="button" value="新增"><br>
<hr>
<table border="1" cellspacing="0" width="800"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><%for (int i = 0; i < brands.size(); i++) {Brand brand = brands.get(i);%>
​<tr align="center"><td><%=brand.getId()%></td><td><%=brand.getBrandName()%></td><td><%=brand.getCompanyName()%></td><td><%=brand.getOrdered()%></td><td><%=brand.getDescription()%></td><td><%=brand.getStatus() == 1 ? "启用":"禁用"%></td><td><a href="#">修改</a> <a href="#">删除</a></td></tr>
​<%}%>
</table>
</body>
</html>
4.2.4 测试

在浏览器地址栏输入 http://localhost:8080/jsp-demo/brand.jsp ,页面展示效果如下

4.3 JSP 缺点

通过上面的案例,我们可以看到 JSP 的很多缺点。

由于 JSP页面内,既可以定义 HTML 标签,又可以定义 Java代码,造成了以下问题:

  • 书写麻烦:特别是复杂的页面

    既要写 HTML 标签,还要写 Java 代码

  • 阅读麻烦

    上面案例的代码,相信你后期再看这段代码时还需要花费很长的时间去梳理

  • 复杂度高:运行需要依赖于各种环境,JRE,JSP容器,JavaEE…

  • 占内存和磁盘:JSP会自动生成.java和.class文件占磁盘,运行的是.class文件占内存

  • 调试困难:出错后,需要找到自动生成的.java文件进行调试

  • 不利于团队协作:前端人员不会 Java,后端人员不精 HTML

    如果页面布局发生变化,前端工程师对静态页面进行修改,然后再交给后端工程师,由后端工程师再将该页面改为 JSP 页面

由于上述的问题, ==JSP 已逐渐退出历史舞台,==以后开发更多的是使用 ==HTML + Ajax== 来替代。Ajax 是我们后续会重点学习的技术。有个这个技术后,前端工程师负责前端页面开发,而后端工程师只负责前端代码开发。下来对技术的发展进行简单的说明

  1. 第一阶段:使用 servlet 即实现逻辑代码编写,也对页面进行拼接。这种模式我们之前也接触过

  2. 第二阶段:随着技术的发展,出现了 JSP ,人们发现 JSP 使用起来比 Servlet 方便很多,但是还是要在 JSP 中嵌套 Java 代码,也不利于后期的维护

  3. 第三阶段:使用 Servlet 进行逻辑代码开发,而使用 JSP 进行数据展示

  4. 第四阶段:使用 servlet 进行后端逻辑代码开发,而使用 HTML 进行数据展示。而这里面就存在问题,HTML 是静态页面,怎么进行动态数据展示呢?这就是 ajax 的作用了。

那既然 JSP 已经逐渐的退出历史舞台,那我们为什么还要学习 JSP 呢?原因有两点:

  • 一些公司可能有些老项目还在用 JSP ,所以要求我们必须动 JSP

  • 我们如果不经历这些复杂的过程,就不能体现后面阶段开发的简单

接下来我们来学习第三阶段,使用 EL表达式JSTL 标签库替换 JSP 中的 Java 代码。

5,EL 表达式

5.1 概述

EL(全称Expression Language )表达式语言,用于简化 JSP 页面内的 Java 代码。

EL 表达式的主要作用是 ==获取数据==。其实就是从域对象中获取数据,然后将数据展示在页面上。

而 EL 表达式的语法也比较简单,==${expression}== 。例如:${brands} 就是获取域中存储的 key 为 brands 的数据。

5.2 代码演示

  • 定义servlet,在 servlet 中封装一些数据并存储到 request 域对象中并转发到 el-demo.jsp 页面。

    @WebServlet("/demo1")
    public class ServletDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 准备数据List<Brand> brands = new ArrayList<Brand>();brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0));brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1));
    ​//2. 存储到request域中request.setAttribute("brands",brands);
    ​//3. 转发到 el-demo.jsprequest.getRequestDispatcher("/el-demo.jsp").forward(request,response);}
    ​@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
    }

    ==注意:== 此处需要用转发,因为转发才可以使用 request 对象作为域对象进行数据共享

  • el-demo.jsp 中通过 EL表达式 获取数据

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>Title</title>
    </head>
    <body>${brands}
    </body>
    </html>
  • 在浏览器的地址栏输入 http://localhost:8080/jsp-demo/demo1 ,页面效果如下:

5.3 域对象

JavaWeb中有四大域对象,分别是:

  • page:当前页面有效

  • request:当前请求有效

  • session:当前会话有效

  • application:当前应用有效

el 表达式获取数据,会依次从这4个域中寻找,直到找到为止。而这四个域对象的作用范围如下图所示

例如: ${brands},el 表达式获取数据,会先从page域对象中获取数据,如果没有再到 requet 域对象中获取数据,如果再没有再到 session 域对象中获取,如果还没有才会到 application 中获取数据。

6,JSTL标签

6.1 概述

JSP标准标签库(Jsp Standarded Tag Library) ,使用标签取代JSP页面上的Java代码。如下代码就是JSTL标签

<c:if test="${flag == 1}">男
</c:if>
<c:if test="${flag == 2}">女
</c:if>

上面代码看起来是不是比 JSP 中嵌套 Java 代码看起来舒服好了。而且前端工程师对标签是特别敏感的,他们看到这段代码是能看懂的。

JSTL 提供了很多标签,如下图

我们只对两个最常用的标签进行讲解,<c:forEach> 标签和 <c:if> 标签。

JSTL 使用也是比较简单的,分为如下步骤:

  • 导入坐标

    <dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version>
    </dependency>
    <dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version>
    </dependency>
  • 在JSP页面上引入JSTL标签库

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
  • 使用标签

6.2 if 标签

<c:if>:相当于 if 判断

  • 属性:test,用于定义条件表达式

<c:if test="${flag == 1}">男
</c:if>
<c:if test="${flag == 2}">女
</c:if>

代码演示:

  • 定义一个 servlet ,在该 servlet 中向 request 域对象中添加 键是 status ,值为 1 的数据

    @WebServlet("/demo2")
    public class ServletDemo2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 存储数据到request域中request.setAttribute("status",1);
    ​//2. 转发到 jstl-if.jsp数据request.getRequestDispatcher("/jstl-if.jsp").forward(request,response);}
    ​@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
    }
  • 定义 jstl-if.jsp 页面,在该页面使用 <c:if> 标签

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head><title>Title</title>
    </head>
    <body><%--c:if:来完成逻辑判断,替换java  if else--%><c:if test="${status ==1}">启用</c:if>
    ​<c:if test="${status ==0}">禁用</c:if>
    </body>
    </html>

    ==注意:== 在该页面已经要引入 JSTL核心标签库

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

6.3 forEach 标签

<c:forEach>:相当于 for 循环。java中有增强for循环和普通for循环,JSTL 中的 <c:forEach> 也有两种用法

6.3.1 用法一

类似于 Java 中的增强for循环。涉及到的 <c:forEach> 中的属性如下

  • items:被遍历的容器

  • var:遍历产生的临时变量

  • varStatus:遍历状态对象

如下代码,是从域对象中获取名为 brands 数据,该数据是一个集合;遍历遍历,并给该集合中的每一个元素起名为 brand,是 Brand对象。在循环里面使用 EL表达式获取每一个Brand对象的属性值

<c:forEach items="${brands}" var="brand"><tr align="center"><td>${brand.id}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.description}</td></tr>
</c:forEach>

代码演示:

  • servlet 还是使用之前的名为 ServletDemo1

  • 定义名为 jstl-foreach.jsp 页面,内容如下:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    ​
    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><title>Title</title>
    </head>
    <body>
    <input type="button" value="新增"><br>
    <hr>
    <table border="1" cellspacing="0" width="800"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr>
    ​<c:forEach items="${brands}" var="brand" varStatus="status"><tr align="center"><%--<td>${brand.id}</td>--%><td>${status.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:if test="${brand.status == 1}"><td>启用</td></c:if><c:if test="${brand.status != 1}"><td>禁用</td></c:if><td><a href="#">修改</a> <a href="#">删除</a></td></tr></c:forEach>
    </table>
    </body>
    </html>
6.3.2 用法二

类似于 Java 中的普通for循环。涉及到的 <c:forEach> 中的属性如下

  • begin:开始数

  • end:结束数

  • step:步长

实例代码:

从0循环到10,变量名是 i ,每次自增1

<c:forEach begin="0" end="10" step="1" var="i">${i}
</c:forEach>

7,MVC模式和三层架构

MVC 模式和三层架构是一些理论的知识,将来我们使用了它们进行代码开发会让我们代码维护性和扩展性更好。

7.1 MVC模式

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

  • M:Model,业务模型,处理业务

  • V:View,视图,界面展示

  • C:Controller,控制器,处理请求,调用模型和视图

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

MVC 好处:

  • 职责单一,互不影响。每个角色做它自己的事,各司其职。

  • 有利于分工协作。

  • 有利于组件重用

7.2 三层架构

三层架构是将我们的项目分成了三个层面,分别是 表现层业务逻辑层数据访问层

  • 数据访问层:对数据库的CRUD基本操作

  • 业务逻辑层:对业务逻辑进行封装,组合数据访问层层中基本功能,形成复杂的业务逻辑功能。例如 注册业务功能 ,我们会先调用 数据访问层selectByName() 方法判断该用户名是否存在,如果不存在再调用 数据访问层insert() 方法进行数据的添加操作

  • 表现层:接收请求,封装数据,调用业务逻辑层,响应数据

而整个流程是,浏览器发送请求,表现层的Servlet接收请求并调用业务逻辑层的方法进行业务逻辑处理,而业务逻辑层方法调用数据访问层方法进行数据的操作,依次返回到serlvet,然后servlet将数据交由 JSP 进行展示。

三层架构的每一层都有特有的包名称:

  • 表现层: com.itheima.controller 或者 com.itheima.web

  • 业务逻辑层:com.itheima.service

  • 数据访问层:com.itheima.dao 或者 com.itheima.mapper

后期我们还会学习一些框架,不同的框架是对不同层进行封装的

7.3 MVC 和 三层架构

通过 MVC 和 三层架构 的学习,有些人肯定混淆了。那他们有什么区别和联系?

如上图上半部分是 MVC 模式,上图下半部分是三层架构。 MVC 模式 中的 C(控制器)和 V(视图)就是 三层架构 中的表现层,而 MVC 模式 中的 M(模型)就是 三层架构 中的 业务逻辑层 和 数据访问层。

可以将 MVC 模式 理解成是一个大的概念,而 三层架构 是对 MVC 模式 实现架构的思想。 那么我们以后按照要求将不同层的代码写在不同的包下,每一层里功能职责做到单一,将来如果将表现层的技术换掉,而业务逻辑层和数据访问层的代码不需要发生变化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/57578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数智税务 | 数电票:带来税务管理五大新挑战、绘就智慧税务征管新蓝图

目录 数电票&#xff0c;带来税务管理五大新挑战 1“集全” 2“管全” 3“算全” 4“备全” 5“控全” 数电票&#xff0c;绘就智慧税务征管新蓝图 1两化 2三端 3四融合 4变革征管方式 5优化征管流程 6提升征管效能 结语 数电票&#xff0c;带来税务管理五大新挑…

氢氧化铝改性打散机、分散机、包覆机、球磨机

表面改性是指在氢氧化铝颗粒表面吸附或包覆一层或多层物质&#xff0c;以改变其表面性质&#xff0c;增强其与基体材料的相容性和界面结合力。 表面改性方法主要分为物理法和化学法&#xff1a; 1.物理法&#xff1a;使用表面活性剂如高级脂肪酸、醇、胺、酯等进行表面包覆处…

【深度学习】Bert下载和使用(以bert-base-uncased为例)

【深度学习】Bert下载和使用&#xff08;以bert-base-uncased为例&#xff09; 代码报错报错原因解决方法解决步骤1.进入Hugging Face&#xff0c;检索bert-base-uncased2.点击Files and versions3.下载文件4.下载的文件放入文件夹5.代码修改 代码报错 bert BertModel.from_p…

JupyterLab,极其强大的下一代notebook!

JupyterLab简介 JupyterLab是Jupyter主打的最新数据科学生产工具&#xff0c;某种意义上&#xff0c;它的出现是为了取代Jupyter Notebook。不过不用担心Jupyter Notebook会消失&#xff0c;JupyterLab包含了Jupyter Notebook所有功能。 JupyterLab作为一种基于web的集成开发环…

MS01SF1 精准测距UWB模组助力露天采矿中的人车定位安全和作业效率提升

在当今矿业行业&#xff0c;随着全球对资源需求的不断增加和开采难度的逐步提升&#xff0c;传统的作业方式面临着越来越多的挑战。露天矿山开采&#xff0c;因其大规模的作业环境和复杂的地形特点&#xff0c;面临着作业人员的安全风险、设备调度的高难度以及资源利用率低下等…

使用 Github 进行项目管理

GitHub 是一个广泛使用的代码托管和协作平台&#xff0c;它提供了强大的工具来支持项目管理和团队协作。在项目开发和工作中&#xff0c;避免不了 Github 的使用&#xff0c;然鹅我一直没有稍微系统地学习过 github 的整个工作流程&#xff0c;对这些操作都是一知半解的&#x…

servlet开发

一、Servelet &#xff08;一&#xff09;Servelet概述 1.概念&#xff1a;Severlet是一门动态web资源开发技术。 2.本质&#xff1a;Severlet本质是一段Java程序&#xff0c;但和Java程序不同的是&#xff0c;Severlet程序无法独立运行&#xff0c;需要放服务器中&#xff…

ArcGIS003:ArcMap常用操作0-50例动图演示

摘要&#xff1a;本文以动图形式介绍了ArcMap软件的基本操作&#xff0c;包括快捷方式创建、管理许可服务、操作界面元素&#xff08;如内容列表、目录树、搜索窗口、工具箱、Python窗口、模型构建器窗口等&#xff09;的打开与关闭、位置调整及合并&#xff0c;设置默认工作目…

链表|反转链表|移除链表元素|链表的中间节点|返回倒数第k个节点|合并两个有序链表(C)

206. 反转链表 用两个指针 p1指向空&#xff0c;p2指向第一个节点 p2的next指向p1&#xff0c;把方向调过来 因为p2的next指向p1&#xff0c;会丢掉后面的节点&#xff0c;所以需要三个节点 前两个指针是为了反转&#xff0c;后一个指针是为了找到下一个节点 p2给给p1&a…

GitGraphPro 图管理系统

1.产品介绍 产品介绍方案 产品名称: GitGraphPro 图管理系统 主要功能: 智能图谱构建版本控制与协作数据分析与可视化自定义模板与导出功能介绍: 1. 智能图谱构建 具体作用:GitGraphPro 利用先进的算法,自动从项目数据

一:时序数据库-Influx应用

目录 0、版本号 1、登录页面 2、账号基本信息 3、数据库案例 4、可视化 5、java案例 0、版本号 InfluxDB v2.4.0 1、登录页面 http://127.0.0.1:8086/signin 账号&#xff1a;自己账号 密码&#xff1a;自己密码 2、账号基本信息 查看用户id和组织id&#xff01;&…

python脚本:十六进制数据小端序转大端序

大多数机器的存储方式都是小端排序&#xff0c;小端序指的是数据的高位&#xff08;偏左边的&#xff09;放在内存中的高地址&#xff08;偏右边的&#xff09;处&#xff0c;这样会导致存放好的数据对于我们看来好像是“倒过来”的 大端序则是我们看上去从左到右的正常排序 例…

流场主动流动控制

对于流场的主动控制而言&#xff0c;其难点主要集中在强化学习的环境搭建过程&#xff0c;如何建立数值仿真与强化学习的信息交互是研究过程中的拦路虎。经过几个星期的研究&#xff0c;已基本实现由pycharm程序数据端向star ccm端的数据传递。其主要过程包括如下过程&#xff…

Django-文件上传

定义&#xff1a; 上传规则-前端【html】&#xff1a; 上传规则-后端【Django】&#xff1a; urlpatterns [path(upload,views.test_upload) ] 例子&#xff1a; settings添加: MEDIA_URL /media/ MEDIA_ROOT os.path.join(BASE_DIR, media) 主路由&#xff1a; urlpa…

kafka-console-ui的简介及安装使用

kafka-console-ui的简介及安装使用 一、kafka-console-ui的简介二、安装kafka-console-ui2.1 源码安装2.2 docker安装 三、kafka-console-ui功能使用3.1、功能特性3.2、 功能介绍3.2.1 集群3.2.2 topic3.2.3 消费组3.2.4 Acl3.2.5 运维 一、kafka-console-ui的简介 kafka-cons…

ONLYOFFICE 8.2 版本产品评测——遥遥领先

知孤云出岫-CSDN博客 目录 产品介绍——篇【1】 一.关于 ONLYOFFICE 桌面编辑器 二.关于 ONLYOFFICE 协作空间 三.关于 ONLYOFFICE 文档 四.关于 ONLYOFFICE的版本介绍 产品新功能——篇【2】 一.关于 ONLYOFFICE的新增功能介绍 二.OLE FICE文档概述 三.PDF编辑器更新 …

星河飞雪网络安全学习笔记-shodan使用7(完结)

学习笔记-shodan使用7 Shodan命令 info shodan info查询账户搜索次数。 Domain shodan domain baidu.com查询ip域名信息 Scan shodan scan submit ip对ip进行实时扫描&#xff0c;类似nmap。 shodan scan list显示扫描信息。 Stats shodan stats --facets ssl.version countr…

【原创分享】详述中间件的前世今生

中间件是一种软件组件&#xff0c;位于应用程序和操作系统之间&#xff0c;通过提供统一的接口和功能来简化开发和管理应用程序、提高应用程序的可靠性和性能。 中间件的前世可以追溯到20世纪80年代的分布式系统和网络技术的发展。在那个时候&#xff0c;随着计算机网络的普及…

Python | Leetcode Python题解之第524题通过删除字母匹配到字典里最长单词

题目&#xff1a; 题解&#xff1a; class Solution:def findLongestWord(self, s: str, dictionary: List[str]) -> str:m len(s)f [[0] * 26 for _ in range(m)]f.append([m] * 26)for i in range(m - 1, -1, -1):for j in range(26):if ord(s[i]) j 97:f[i][j] iel…

论文翻译 | PROMPTAGATOR : FEW-SHOT DENSE RETRIEVAL FROM 8 EXAMPLES

摘要 最近的信息检索研究主要集中在如何从一个任务&#xff08;通常有丰富的监督数据&#xff09;转移到其他各种监督有限的任务上&#xff0c;其隐含的假设是从一个任务可以泛化到所有其他任务。然而&#xff0c;这忽略了这样一个事实&#xff0c;即存在许多多样化和独特的检索…