[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时的流程
-
浏览器第一次访问
hello.jsp
页面 -
tomcat
会将hello.jsp
转换为名为hello_jsp.java
的一个Servlet
-
tomcat
再将转换的servlet
编译成字节码文件hello_jsp.class
-
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 是我们后续会重点学习的技术。有个这个技术后,前端工程师负责前端页面开发,而后端工程师只负责前端代码开发。下来对技术的发展进行简单的说明
-
第一阶段:使用
servlet
即实现逻辑代码编写,也对页面进行拼接。这种模式我们之前也接触过 -
第二阶段:随着技术的发展,出现了
JSP
,人们发现JSP
使用起来比Servlet
方便很多,但是还是要在JSP
中嵌套Java
代码,也不利于后期的维护 -
第三阶段:使用
Servlet
进行逻辑代码开发,而使用JSP
进行数据展示 -
第四阶段:使用
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 模式
实现架构的思想。 那么我们以后按照要求将不同层的代码写在不同的包下,每一层里功能职责做到单一,将来如果将表现层的技术换掉,而业务逻辑层和数据访问层的代码不需要发生变化。
相关文章:

[java][基础]JSP
目标: 理解 JSP 及 JSP 原理 能在 JSP中使用 EL表达式 和 JSTL标签 理解 MVC模式 和 三层架构 能完成品牌数据的增删改查功能 1,JSP 概述 JSP(全称:Java Server Pages):Java 服务端页面。是一种动态的…...

《测绘学报》
《测绘学报》 办刊宗旨:尊重科学、弘扬学术、追求卓越、求实创新。60多年来,《测绘学报》作为承载着测绘地理信息科学技术和科研成果的载体,作为测绘地理信息行业人才培养和学术交流的阵地,坚持把学术论文的质量放在期刊工作的重要…...

代码随想录之链表刷题总结
目录 1.链表理论基础 2.移除链表元素 3.设计链表 4.翻转链表 5.两两交换链表中的节点 6.删除链表中的第N个节点 7.链表相交 8.环形链表 1.链表理论基础 链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域…...

Python爬虫的“京东大冒险”:揭秘商品类目信息
开篇:欢迎来到Python的奇幻森林 在这个数据驱动的时代,我们就像一群探险家,穿梭在数字的森林中,寻找着隐藏的宝藏——商品类目信息。今天,我们将带领你一起,用Python这把锋利的剑,深入京东的神…...

双目视觉标定——1原理与实践
0 前言 双目视觉定位是目前机器(机器人)等领域中使用得非常广泛的视觉定位技术,双目视觉是模拟人的视觉系统利用两个不同位置的摄像头的视差来确定物体的位置。由于有需要采集两个摄像头的图像共同参与计算,所以双目相机装配要求…...

【设计模式系列】代理模式(八)
一、什么是代理模式 代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式在不直接访问实际对象的情况下,提供了对目标对象的间接访问。通过引入一个代理对象来间接操作实际对…...

微服务架构设计的初次尝试——基于以太坊智能合约 + NestJS 微服务的游戏社区与任务市场系统:架构设计
TMDOG微服务架构设计的初次尝试——基于以太坊智能合约 NestJS 微服务的游戏社区与任务市场系统:架构设计 一、开发背景及目的 随着区块链技术的蓬勃发展以及去中心化概念的兴起,越来越多的开发者开始探索如何将区块链应用到实际业务场景中࿰…...

“北斗+实景三维”,助力全域社会治理
在国家治理体系和治理能力现代化的大背景下,全域社会治理成为提升国家治理效能的关键。“北斗实景三维”技术组合,为全域社会治理提供了新的技术支撑和解决方案。本文将探讨这一技术如何助力全域社会治理,以及其在实际应用中的潜力和挑战。 …...

#渗透测试#SRC漏洞挖掘# 信息收集-常见端口及谷歌语法
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...

如何使用java雪花算法在分布式环境中生成唯一ID?
引言 在现代分布式系统中,生成唯一标识符(ID)是一个常见的需求。传统的自增ID在分布式环境中会导致冲突,因此需要一种能够在分布式系统中生成全局唯一ID的算法。 雪花算法(Snowflake)就是为了解决这个问题而提出的一种高效的ID生成算法。本文将详细介绍雪花算法的原理、…...

【php常用公共函数】php获取指定时间段相差几小时,几分钟,几秒
实现代码 <?php function diffTime($datetime1, $datetime2) {// 确保 $datetime1 总是小于或等于 $datetime2if (strtotime($datetime1) > strtotime($datetime2)) {$tmp $datetime2;$datetime2 $datetime1;$datetime1 $tmp;}// 转换为时间戳$timestamp1 strtotim…...

图文深入介绍Oracle DB link(一)
1. 引言: 本文图文深入介绍Oracle DB link,先介绍基本概念。 2.DB link的定义 数据库链接(Database Link,简称 DB Link)是 Oracle 数据库中的一个重要功能。它是一种在一个 Oracle 数据库实例中访问另一个 Oracle 数…...

Uniswap/v2-core使用及其交易流程
Uniswap是一个开源的去中心化的交易所,在github上面有以下重要仓库: uniswap-v2-core: 币对池pair的核心智能合约。这个repository包含了Uniswap的币对池pair的所有核心逻辑,增加流动性、减少流动性等。uniswap-v2-periphery&…...

clickhouse运维篇(二):多机器手动部署ck集群
熟悉流程并且有真正部署需求可以看一下我的另一篇简化部署的文章,因为多节点配置还是比较麻烦的先要jdk、zookeeper,再ck,还有各种配置文件登录不同机器上手动改配置文件还挺容易出错的。 clickhouse运维篇(三)&#x…...

OpenCV视觉分析之目标跟踪(7)目标跟踪器类TrackerVit的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 VIT 跟踪器由于特殊的模型结构而变得更快且极其轻量级,模型文件大约为 767KB。模型下载链接:https://github.com/opencv/…...

Java 实现 RESTful 风格的 Web 服务详解
前言 RESTful(Representational State Transfer)风格的 API 已经成为现代 Web 服务的标准。它通过简单的 HTTP 方法和资源定位来提供了一种高度可扩展和易于维护的服务接口。Java 作为一种功能强大且广泛使用的编程语言,提供了多种框架来实现…...

18.网工入门篇--------今天介绍下广域网技术
广域网(Wide Area Network,WAN)是一种能连接多个城市、国家甚至横跨几个洲,提供远距离通信的网络。以下是关于广域网技术的详细介绍: 广域网的组成: 结点交换机:这是广域网的核心设备࿰…...

鸿蒙原生应用开发及部署:首选华为云,开启HarmonyOS NEXT App新纪元
目录 前言 HarmonyOS NEXT:下一代操作系统的愿景 1、核心特性和优势 2、如何推动应用生态的发展 3、对开发者和用户的影响 华为云服务在鸿蒙原生应用开发中的作用 1、华为云ECS C系列实例 (1)全维度性能升级 (2ÿ…...

Spring JdbcTemplate详解
文章目录 Spring JdbcTemplate详解一、引言二、配置JdbcTemplate1、引入依赖2、配置数据库连接池3、配置JdbcTemplate 三、使用JdbcTemplate操作数据库1、添加数据2、查询数据查询某个值根据条件查询返回某个对象查询对象集合 四、总结 Spring JdbcTemplate详解 一、引言 在J…...

Docker篇(Docker安装)
目录 一、Centos7.x 1. yum 包更新到最新 2. 安装需要的软件包 3. 设置 yum 源为阿里云 4. 安装docker 5. 安装后查看docker版本 6. 设置ustc镜像源 二、CentOS安装Docker 前言 1. 卸载(可选) 2. 安装docker 3. 启动docker 4. 配置镜像加速 …...

Pytorch 实现图片分类
CNN 网络适用于图片识别,卷积神经网络主要用于图片的处理识别。卷积神经网络,包括一下几部分,输入层、卷积层、池化层、全链接层和输出层。 使用 CIFAR-10 进行训练, CIFAR-10 中图片尺寸为 32 * 32。卷积层通过卷积核移动进行计…...

得物App获评新奖项,正品保障夯实供应链创新水平
近日,得物App再度获评新奖项——“2024上海市供应链创新与应用优秀案例”。 本次奖项为上海市供应链领域最高奖项,旨在评选出在供应链创新成效上处于领先地位、拥有成功模式和经验的企业。今年以来,得物App已接连获得“上海市质量金奖”、“科…...

【数据结构-邻项消除】力扣735. 小行星碰撞
给定一个整数数组 asteroids,表示在同一行的小行星。 对于数组中的每一个元素,其绝对值表示小行星的大小,正负表示小行星的移动方向(正表示向右移动,负表示向左移动)。每一颗小行星以相同的速度移动。 找…...

002-Kotlin界面开发之Kotlin旋风之旅
Kotlin旋风之旅 Compose Desktop中哪些Kotlin知识是必须的? 在学习Compose Desktop中,以下Kotlin知识是必须的: 基础语法:包括变量声明、数据类型、条件语句、循环等。面向对象编程:类与对象、继承、接口、抽象类等。…...

VMware Workstation Pro for Personal Use (For Windows)
这是从broadcom.com网下载的个人版本的Vmware 17.6.1,存分享不要分。 VMware-workstation-full-17.6.1-24319023.exe(447.93 MB) Build Number: 24319023 Oct 08, 2024 07.33AM SHA2: f95429e395a583eb5ba91f09b040e2f8c53a5e7aa37c4c6bfcaf82115a8…...

论文 | PROMPTAGATOR : FEW-SHOT DENSE RETRIEVAL FROM 8 EXAMPLES
1. 背景信息 在信息检索领域,传统的方法往往依赖于大量的标注数据来训练模型,以便在各种任务中表现良好。然而,许多实际应用中的监督数据是有限的,尤其是在不同的检索任务中。最近的研究开始关注如何从一个拥有丰富监督数据的任务…...

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

企业SRC挖掘选择与信息收集指南
内容预览 ≧∀≦ゞ 企业SRC挖掘选择与信息收集指南导语1. 企业SRC的选择2. 信息收集2.1 集团与子公司2.2 小程序与APP2.3 Web端信息收集 3. 信息收集常用模板总结 企业SRC挖掘选择与信息收集指南 导语 近年来,企业的安全响应中心(SRC)已逐渐…...

Golang | Leetcode Golang题解之第524题通过删除字母匹配到字典里最长单词
题目: 题解: func findLongestWord(s string, dictionary []string) (ans string) {m : len(s)f : make([][26]int, m1)for i : range f[m] {f[m][i] m}for i : m - 1; i > 0; i-- {f[i] f[i1]f[i][s[i]-a] i}outer:for _, t : range dictionary …...

【DBeaver】连接带kerberos的hive[Apache|HDP]
目录 一、安装配置Kerberos客户端环境 1.1 安装Kerberos客户端 1.2 环境配置 二、基于Cloudera驱动创建连接 三、基于Hive原生驱动创建连接 一、安装配置Kerberos客户端环境 1.1 安装Kerberos客户端 在Kerberos官网下载,地址如下:https://web.mit.edu/kerberos…...