一文带你吃透JSP,增删改查实战案例详细解读
前言
不得不说,JSP 现在已经是一门十分老旧的技术了,学习编程时,不仅要学习优秀的前言技术,还要对基础有一定的把握,所以学习 JSP 时,我们只做了解,不用刨根问底花费大量的时间,得不偿失。
我们主要从以下几个方面学习 JSP 技术:
- 理解 JSP 及其原理
- 学会使用 EL 表达式和 JSTL 标签
- 理解 MVC 模式和三层架构(重点)
学习 JSP 到什么程度呢?我们只需要能够使用 JSP 相关技术能够实现简单数据的增删改查即可。
JSP 概述
JSP,Java Server Pages,指的是 Java 服务端页面,是一种动态的网页技术,其中既可以定义 HTML,CSS,JavaScript 静态内容,也可以使用 Java 代码定义动态内容。通俗的说,JSP = HTML + Java 。下面就是一个最简单的 JSP 代码:
<html>
<head>
<title>title</title>
</head>
<body>
<h1>HelloWorld</h1>
<%
System.out.println("HelloWorld!");
%>
</body>
</html>
上面的例子中,html 里面的内容会在浏览器渲染,而 Java 代码的输出语句会打印在 idea 控制台。
那么 JSP 到底是用来做什么的?我们如何实现不同用户登录网页显示不同的信息呢?例如,在页面上显示登录的用户名:
在 Servlet 中,我们使用 write 对象向浏览器写数据,html 标签可以作为字符串传入 write() 方法中。但是,当向页面写出大量数据时,代码显得十分的混乱不堪,并且后期后期维护成本极大。而 JSP 就结局了这个问题,在 JSP 代码中可以直接使用 html 标签,动态数据也可以使用 Java 代码展示,大大的简化了开发,避免了在 Servlet 中直接输出 html 标签。
JSP快速入门
搭建环境
在 idea 中创建一个 Maven Web 项目,项目结构如下:
在 pom.xml 添加 Servlet 的依赖坐标和 TomCat 插件坐标,如下:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.chengzi</groupId>
<artifactId>jsp-demo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>jsp-demo Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<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>
<finalName>jsp-demo</finalName>
</build>
</project>
导入JSP依赖
在 pom.xml 中添加 JSP 的依赖坐标,如下:
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
创建 JSP 页面
在项目的 webapps 文件目录下创建 jsp 页面,如图:
通过上面的操作创建一个名为 hello.jsp 的页面。
编写代码
在 hello.jsp 中书写 HTML 标签和 Java 代码,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>HelloWorld</h1>
<%
System.out.println("helloWorld!");
%>
</body>
</html>
测试
启动 Tomcat 服务器,在浏览器访问 http://localhost:8080/jsp-demo/hello.jsp
,结果如下:
JSP原理
之前,我们在 jsp 中不仅编写了 html 标签,还编写了 Java 代码,为什么呢?其实,JSP 本质上就是一个 Servlet。要弄明白这个问题,我们就要研究 jsp 的执行流程。
在上面的例子中,浏览器第一次访问 heelo.jsp 页面时,Tomcat 会将 hello.jsp 装换为名为 hello_jsp.java 的一个Servlet, 然后 这个 Servlet 会被 TomCat 编译为字节码文件 hello_jsp.class 。TomCat 会执行该字节码文件向外提供服务。
此时在项目磁盘目录下找到 target\tomcat\work\Tomcat\localhost\jsp-demo\org\apache\jsp
,在这个文件目录下就可以看到装换后的 Servlet 和编译后的 .class
文件。如图:
打开 hello_jsp.java 文件查看源码,如图:
可以发现转换后的 hello_jsp 类继承自 HttpJspBase ,其实 HttpJspBase 类是继承自 HttpServlet 的,我们可以查看 TomCat 源码,所以 hello_jsp 类间接继承了 HttpServlet ,也就是说,JSP 容器将 JSP 文件装换成了一个 Servlet。
在 hello_jsp 类中还有一个 _jspService() 方法,该方法和 Servlet 中的 service 方法类似,在每次访问警示牌 jsp 时自动执行。如图:
在 _jspService() 方法中可以看到完浏览器中写的标签和 Java 代码,如下:
不难看出,在 <%...%>
中的 Java 代码被放到了 _jspService() 方法中,这段 Java 代码被称为 JSP 脚本。
JSP 脚本
JSP 脚本用于在 JSP 页面内定义 Java 代码,之前案例中使用到的 Java 代码就是定义在 JSP 脚本中的,JSP 脚本一共分为 3 类:
<%…%> 内容会直接放到 _jspService() 方法中
<%=…%> 内容或被放到 out.print() 中,作为该的方法的参数
<%!..%> 内容会被放到 _jspService() 方法之外,被类直接包括
代码演示:
第一步:在 hello.jsp 中编写代码:
<%
System.out.println("hello");
int i = 3;
%>
通过浏览器访问该资源,查看转换后的 hello_jsp.java 源代码,不难发现 i 变量被定义在 _jspService() 方法中,如图:
第二步:在 hello.jsp 中编写代码:
<%="hello"%>
<%=i%>
通过浏览器访问该资源,查看转换后的 hello_jsp.java 源代码,不难发现 i 变量成为了 out.print() 方法的参数,并且这两个数据被发送到了浏览器展示给用户,如图:
第三步:在 hello.jsp 中编写代码:
<%!
void show(){}
String name = "zhangsan";
%>
通过浏览器访问该资源,查看转换后的 hello_jsp.java 源代码,不难发现该部分被放到了类的成员部分,如图:
实战案例
使用 JSP 在浏览器以表格的形式展示学生信息的数据,这里的数据应该使用 MyBatis 在数据库中查找,但是这里只是简单的演示 JSP 的使用,所以我们省略了对数据库的操作,直接将数据封装到 Student 对象中并存放在集合中。
首先我们在 org.chengzi.pojo 包下创建一个实体类 Student 。在 Java 文件目录右击 new / Java class ,创建包和类。如下:
public class Student {
private int id;
private String name;
private String gender;
private int scoreEnglish;
private int scoreMath;
//省略了getter和setter方法以及重写的Object类的toString方法
}
在项目 webapps 目录下创建 student.jsp,在此文件中写 html 标签和 Java 代码,我们可以先将数据写死,方便展示在浏览器。如下:
<%@ 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>
</tr>
<tr align="center">
<td>1</td>
<td>张三</td>
<td>男</td>
<td>100</td>
<td>100</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td>2</td>
<td>李四</td>
<td>男</td>
<td>100</td>
<td>100</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td>3</td>
<td>王五</td>
<td>女</td>
<td>100</td>
<td>100</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</table>
</body>
</html>
在浏览器访问该资源,效果如下:
准备需要动态展示到浏览器的数据,这里省略了从数据库查询数据,我们直接将数据封装在 Student 对象中,并将所有对象放在集合中。例如:
<%
// 查询数据库
List<Student> brands = new ArrayList<Student>();
brands.add(new Student(1,小张,女,85,89));
brands.add(new Student(2,小樊,女,98,87));
brands.add(new Student(3,小李,男,100,99));
%>
上面我们使用固定的数据发送到浏览器展示,为了动态的展示数据,我们要使用 Java 代码来动态的获取数据,而在 JSP 页面中,Java 代码要写在 JSP 脚本中,如下:
<%@ page import="org.chengzi.pojo.Student" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 查询数据库
List<Student> students = new ArrayList<Student>();
students.add(new Student(1, "小张", "男", 80, 85));
students.add(new Student(2, "小李", "女", 98, 87));
students.add(new Student(3, "小樊", "女", 98, 100));
%>
<!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>
</tr>
<%
for (int i = 0; i < students.size(); i++) {
//获取集合中的 每一个 Brand 对象
Student student = students.get(i);
%>
<tr align="center">
<td><%=student.getId()%>
</td>
<td><%=student.getName()%>
</td>
<td><%=student.getGender()%>
</td>
<td><%=student.getScoreEnglish()%>
</td>
<td><%=student.getScoreMath()%>
</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<%
}
%>
</table>
</body>
</html>
此时,数据就会被动态的展示到浏览器页面,不难看出,其实 JSP 脚本标签就是在分割 Java 代码,在标签内是 Java 代码,在标签外则是 html 语句,如图:
JSP缺点
不难看出,JSP 开发还是有很多的缺点的,首先,既然在 jsp 文件中既可以写 html 标签,有可以写 Java 代码,导致了书写麻烦和阅读麻烦的问题。并且其运行要依赖各种环境,例如 jre,jsp 容器,JavaEE 等等,导致其程序变得十分复杂。
JSP 会自动生成 .java 文件和 .class 文件占用了磁盘空间,而运行 .class 文件占用内存。在程序出错以后,我们一般要找到自动生成的 .java 文件进行调试,导致了调试困难的问题。
另外,把 Java 代码和 html 代码混在一个文件中是非常不利于团队开发的,如果页面出现问题,首先前端开发工程师修改静态页面,然后由后端开发来将该页面修改为 JSP 页面,这不是我们想看到的合作开发方式。
由于 JSP 存在着很多的确定,并且随着软件技术的发展,JSP 已经逐渐退出历史的舞台了,后面我们会学习新的技术 AJAX 来替代前面的方式,有了这个技术以后,前端工程师只负责前端页面的开发,而后端工程师只负责后端代码的开发,职责单一高效。
当然,我们并不是说后端开发就不用学习前端的知识,即使你是专注于后端开发,前端的知识你同样要了解,任何一个说后端不用了解前端知识的说法都是不负责任大额。
发展阶段
下面我们看一下服务器页面技术的发展过程,聊聊为什么 JSP 既然已经被淘汰,为什么我们还要学习呢?
第一阶段:
使用 Servlet 技术实现逻辑代码的编写,也对页面进行拼接。
第二阶段:
随着技术的发展,出现了 JSP,JSP 确实使用比 Servlet 方便了很多,但是随着时间的发展,JSP 的很多确定都暴露出来了。
第三阶段:
使用 Servlet 进行逻辑开发,使用 JSP 进行数据的展示。
第四阶段:
使用 Servlet 进行后端逻辑代码的开发,使用 HTML 进行数据的展示,html 是静态页面,为了展示动态数据,出现了新的技术 AJAX。
现在我们学习 JSP 时,大概有两个原因,一是一些公司的老项目仍然使用了 JSP,所以为了项目的维护,我们不得不学习,另外,学习技术是一个循序渐进的过程,我们必须一步一步的学习,虽然 JSP 老旧过时,但是其中的编程思想使我们学习编程过程中应该了解的。
前面说到,使用 Servlet 进行逻辑开发,使用 JSP 来获取数据,遍历展现数据,这样的方式解决了 JSP 页面中 Java 代码混乱的问题,接下来看一看如何使用 EL 表达式和 JSTL 标签库来替代 JSP 页面中的 Java 代码。
EL 表达式
概述
EL ,Expression Language,称为表达式语言,用于简化 JSP 页面内的 Java 代码。EL 表达式的主要作用是获取数据,期数就是从域对象中获取数据,然后将数据展示在页面上。
EL 表达式的语法比较简单,使用${expression}
,例如 ${student} 就是获取域对象中存储的 key 为 student 的数据。
实战案例
定义一个 Servlet,在 Servlet 中封装数据并存储到 request 域对象中并转发到 el-demo.jsp 页面。
@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//准备数据
List<Student> students = new ArrayList<Student>();
students.add(new Student(1,"张三","男",100,100));
students.add(new Student(2,"李四","女",98,98));
//存储到request域对象中(使用request转发,将request作为域对象)
request.setAttribute("students",students);
//发送到 el-demo.jsp 页面
request.getRequestDispatcher("/el-demo.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
在 el-demo.jsp 中通过 EL 表达式来获取数据,EL 表示式后面不需要加分号。例如:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${students}
</body>
</html>
如果 JSP 中没有接收到 Servlet 共享的数据,如图:
解决方法:在 JSP 代码中添加:
isELIgnored="false"
添加位置在:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
域对象
上面我们在 Servlet 中使用转发将 request 作为域对象进行数据共享,那么什么是域对象?域对象有哪些呢?
在 JavaWeb 中,一共有四大域对象,分别是:
- page:当前页有效
- request:当前请求有效
- session:当前会话有效(后面聊什么是会话)
- application:当前应用有效
如图所示:
EL 表达式获取数据,会一次从四个域中寻找,知道找到为止。
例如,例如 EL 表达式 ${students} 会先从 page 域对象中获取数据,如果没有找到,再去 request 域对象中获取数据,一次寻找,直到找到数据。
JSTL 标签
前端开发工程师每天都在和标签打交道,他们对标签是更加敏感的,所以出现了 JSTL 标准标签库,使用标签替代了 JSP 页面中的 Java 代码,提高了代码的可读性。如下:
<c:if test="${flag == 1}">
男
</c:if>
<c:if test="${flag == 2}">
女
</c:if>
JSTL,Jsp Standarded Tag Library,JSP 标准标签库,其中提供了丰富的标签用于取代 JSP 页面中的 Java 代码,例如:
标签 | 描述 |
---|---|
<c:out> | 用于在JSP中显示数据,就像<%= … > |
<c:set> | 用于保存数据 |
<c:remove> | 用于删除数据 |
<c:catch> | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
<c:if> | 与我们在一般程序中用的if一样 |
<c:choose> | 本身只当做<c:when> 和<c:otherwise> 的父标签 |
<c:when> | <c:choose> 的子标签,用来判断条件是否成立 |
<c:otherwise> | <c:choose> 的子标签,接在<c:when> 标签后,当<c:when> 标签判断为false时被执行 |
<c:import> | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
<c:forEach> | 基础迭代标签,接受多种集合类型 |
<c:forTokens> | 根据指定的分隔符来分隔内容并迭代输出 |
<c:param> | 用来给包含或重定向的页面传递参数 |
<c:redirect> | 重定向至一个新的URL. |
<c:url> | 使用可选的查询参数来创造一个URL |
使用 JSTL 之前要先导入依赖和引入标签库,例如在 pom.xml 中添加依赖坐标:
<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" %>
下面举例练习几个常用的标签。
<c:if>
标签相当于 Java 中的if判断语句,示例:定义一个 Servlet,在 Servlet 中向 request 域对象中添加键为 status,值为 1 的数据。
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//存储数据到request域对象中
request.setAttribute("status",1);
//发送到 jstl.jsp页面
request.getRequestDispatcher("/jstl.jsp").forward(request,response);
}
定义 jstl.jsp 页面,使用 <c:if>
标签进行判断:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ 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>
<forEach>
标签相当于 Java 中的 for 循环,Java 中有普通 for 循环和增强 for 循环,其实在 JSTL 中的循环标签也有两种用法:
用法1
第一种用法类似于 Java 中的普通 for 循环,其中主要使用到的属性有:
- begin:开始数
- end:结束数
- step:步长
- var:循环变量
示例:
<c:forEach begin="0" end="10" step="1" var="i">
${i}
</c:forEach>
用法2
第二种用法类似于 Java 中的增强 for 循环,主要使用的属性有:
- items:被遍历的容器
- var:遍历产生的零时变量
- varStatus:遍历状态对象
示例:
<c:forEach items="${students}" var="student">
<tr align="center">
<td>${student.id}</td>
<td>${student.brandName}</td>
<td>${student.companyName}</td>
<td>${student.description}</td>
</tr>
</c:forEach>
上面例子中,首先从域对象中获取了 students 数据,该数据是一个集合,遍历结合,并给集合中每一个对象起名为 student ,在循环中使用了 EL 表达式获取每一个 Student 对象的属性值。
你问我青春还剩几年?我的回答是,趁现在,正当时。身边朋友都在问我怎样学好一门编程语言,怎样学好Java?怎样通过 Java 找到一份满意的工作?推荐学习此专栏:Java编程基础教程系列(零基础小白搬砖逆袭)
下期见。
相关文章:

并发编程下的集合:数组寻址、LinkedList、HashMap、ConcurrentHashMap
如果发现hash取模后的数组索引位下无元素则直接新增,若不是空那就说明存在hash冲突,则判断数组索引位链表结构中的第一个元素的key以及hash值是否与新的key一致则直接覆盖,若不一致则判断当前的数组索引下的链表结构是否为红黑树,若为红黑树则走红黑树的新增方法,若不为红黑树则遍历当前链表结构,遍历中发现某个节点元素的next为null是则直接将新元素指针与next进行关联,若在遍历到next为空前判断到,某个节点的key以及key的hash值与新的key与新的keyhash值一致时则走覆盖。

【日常开发之插件篇】IDEA plugins 神器助我!!
今早因为老代码的一些bug让我突然觉得Idea的一些插件特别好用,我准备将我平时所用到的一些插件做个推荐以及记录。

【日常开发之FTP】Windows开启FTP、Java实现FTP文件上传下载
FTP是一个专门进行文件管理的操作服务,一般来讲可以在任意的操作系统之中进行配置,但是如果考虑到简便性,一般来讲可以直接在Linux系统下进行安装。FTP (File Transfer Protocol、文件传输协议)是TCP/IP协议中的一部分,属于应用层协议。使用FTP最主要的功能是对文件进行管理,所以在FTP内部对于文件支持有两种传输模式:文本模式(ASCII、默认)和二进制模式(Binary),通常文本文件使用ASCIl模式,而对于图片、视频、声音、压缩等文件则会使用二进制的方式进行传输。

【Linux之升华篇】Linux内核锁、用户模式与内核模式、用户进程通讯方式
alloc_pages(gfp_mask, order),_ _get_free_pages(gfp_mask, order)等。字符设备描述符 struct cdev,cdev_alloc()用于动态的分配 cdev 描述符,cdev_add()用于注。外,还支持语义符合 Posix.1 标准的信号函数 sigaction(实际上,该函数是基于 BSD 的,BSD。从最初的原子操作,到后来的信号量,从。(2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的。

【Mongdb之数据同步篇】什么是Oplog、Mongodb 开启oplog,java监听oplog并写入关系型数据库、Mongodb动态切换数据源
oplog是local库下的一个固定集合,Secondary就是通过查看Primary 的oplog这个集合来进行复制的。每个节点都有oplog,记录这从主节点复制过来的信息,这样每个成员都可以作为同步源给其他节点。Oplog 可以说是Mongodb Replication的纽带了。

【日常开发之Windows共享文件】Java实现Windows共享文件上传下载
下拉框选择你选择的用户点击添加,然后共享确定。创建一个文件夹然后点击属性界面,点击共享。maven版本存在于SMB协议的兼容问题。首先开启服务,打开控制面板点击程序。点击启用或关闭Windows功能。我这边是专门创建了一个用户。SMB1.0选中红框内的。

rust wasm入门
demo## 编译 Rust 为 WebAssembly在本教程中,我们将使用 Rust 的 npm 包构建工具 wasm-pack 来构建一个 npm 包。

iced 入门一
本教程的目标是创建一个简单的购物清单应用程序。我们希望允许添加和删除购物清单中的项目。在编写代码之前,我们必须首先了解 Iced 构建的结构:Elm 架构。它是 GUI 库使用的架构,最初用于 Elm 编程语言。它的核心原则很简单。它围绕三个概念构建:模型、视图和更新。

注解annotation
Kubernetes的系统组件(例如,kube-scheduler、kube-controller-manager、kube-apiserver、kubectl 或其他第三方组件)向用户的Kubernetes对象添加注解时,必须指定一个前缀。注解(annotation)可以用来向 Kubernetes 对象的 metadata.annotations 字段添加任意的信息。除了使用注解,您也可以将这类信息存放在一个外部的数据库,然而,在使用、分享这些信息的时候,可能会变得难以管理。

Rust XTask 模式介绍与应用
XTask(扩展任务)是一种在Rust项目中定义和执行自定义构建任务的方式。它通过创建一个独立的Rust库或二进制项目来封装这些任务,利用Rust语言的强类型、安全性和跨平台能力,使得构建流程更加健壮、可读和可维护。

CXFServlet类的作用
CXFServlet是Apache CXF框架中的一个核心组件,用于处理HTTP请求并将它们转换为Web服务调用。通过配置CXFServlet,你可以轻松地部署和管理SOAP和RESTful Web服务。

@Scheduled注解的scheduler属性什么作用
注解是 Spring Framework 提供的一种机制,用于定义计划任务,即周期性执行的任务。 注解可以应用于方法上,以指示 Spring 容器在特定的时间间隔或按照某种调度规则来调用该方法。 属性是 注解的一个可选属性,它的作用是允许开发者指定一个自定义的 对象来控制任务的调度方式。默认情况下, 注解使用 Spring 内部的 来执行任务,但如果需要更高级的定制化需求,可以通过 属性指定一个自定义的 实现。自定义调度器:共享调度器资源:高级调度需求:假设你想使用 作为调度器,并且希望所有带有

ModuleNotFoundError: No module named ‘qcloud_cos‘
是腾讯云提供的一个Python SDK,用于与腾讯云对象存储(COS)服务进行交互。使用pip安装qcloud_cos报以下错误。这个错误表示Python无法找到名为。

过滤器、拦截器、aop的先后顺序和作用范围&拦截器preHandle(),postHandle(),afterComplation()方法执行顺序
在Spring框架中,过滤器(Filter)、拦截器(Interceptor)和面向切面编程(AOP)都是用于处理请求和处理流程的组件,但它们的作用范围和触发时机有所不同。下面我会解释这三者的先后顺序和作用范围。执行顺序:请注意,这个顺序可能因具体的配置和使用的技术而有所不同。在实际应用中,建议根据项目的具体需求来合理配置和使用这些组件。拦截器执行流程图:实现拦截器需要实现这个接口,这个 接口中有三个默认方法,这三个方法的执行顺序:我们实现接口然后重写这三个方法,就会在对应的时机被自动执行。这里就是调用处理

Zookeeper概要、协议、应用场景
Zoopkeeper提供了一套很好的分布式集群管理的机制,就是它这种基于层次型的目录树的数据结构并对树中的节点进行有效管理,从而可以设计出多种多样的分布式的数据管理模型,作为分布式系统的沟通调度桥梁。

spring.factories文件的作用
即spring.factories文件是帮助spring-boot项目包以外的bean(即在pom文件中添加依赖中的bean)注册到spring-boot项目的spring容器中。在Spring Boot启动时,它会扫描classpath下所有的spring.factories文件,加载其中的自动配置类,并将它们注入到Spring ApplicationContext中,使得项目能够自动运行。spring.factories文件是Spring Boot自动配置的核心文件之一,它的作用是。

Spring事务七大传播机制与五个隔离级别,嵌套事务
如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。

常见的七种加密算法及实现
**数字签名**、**信息加密** 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、`oauth` 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 **签名加密算法** 来达到业务目标。这里简单的给大家介绍几种常见的签名加密算法和一些典型场景下的应用。## 正文### 1. 数字签名**数字签名**,简单来说就是通过提供 **可鉴别** 的 **数字信息** 验证 **自身身份** 的一种方式。一套 **数字签名** 通常定义两种 **互补

7min到40s:SpringBoot 启动优化实践
然后重点排查这些阶段的代码。先看下。

SpringBoot系列教程之Bean之指定初始化顺序的若干姿势
之前介绍了@Order注解的常见错误理解,它并不能指定 bean 的加载顺序,那么问题来了,如果我需要指定 bean 的加载顺序,那应该怎么办呢?本文将介绍几种可行的方式来控制 bean 之间的加载顺序。

在Java中使用WebSocket
WebSocket是一种协议,用于在Web应用程序和服务器之间建立实时、双向的通信连接。它通过一个单一的TCP连接提供了持久化连接,这使得Web应用程序可以更加实时地传递数据。WebSocket协议最初由W3C开发,并于2011年成为标准。

3种方案,模拟两个线程抢票
在多线程编程中,资源竞争是一个常见的问题。资源竞争发生在多个线程试图同时访问或修改共享资源时,可能导致数据不一致或其他并发问题。在模拟两个线程抢票的场景中,我们需要考虑如何公平地分配票,并确保每个线程都有机会成功获取票。本篇文章将通过三种方式来模拟两个线程抢票的过程,以展示不同的并发控制策略。使用 Synchronized 来确保一次只有一个线程可以访问票资源。使用 ReentrantLock 来实现线程间的协调。使用 Semaphore 来限制同时访问票的线程数量。

替代Druid,HakariCP 为什么这么快?
这次源码探究,真的感觉看到了无数个小细节,无数个小优化,积少成多。平时开发过程中,一些小的细节也一定要“扣”。

Java中volatile 的使用场景有哪些?
volatile是一种轻量级的同步机制,它能保证共享变量的可见性,同时禁止重排序保证了操作的有序性,但是它无法保证原子性。所以使用volatilevolatile。

JDK22 正式发布了 !
Java 22 除了推出了新的增强功能和特性,也获得 Java Management Service (JMS) 的支持,这是一项新的 Oracle 云基础设施远程软件服务(Oracle Cloud Infrastructure, OCI) 原生服务,提供统一的控制台和仪表盘,帮助企业管理本地或云端的 Java 运行时和应用。使包含运行时计算值的字符串更容易表达,简化 Java 程序的开发工作,同时提高将用户提供的值编写成字符串,并将字符串传递给其他系统的程序的安全性。支持开发人员自由地表达构造器的行为。

Jackson 用起来!
你可以创建自定义序列化器和反序列化器以自定义特定字段或类的序列化和反序列化行为。为此,请创建一个实现或接口的类,并在需要自定义的字段或类上使用和注解。@Override// ...其他代码...优势性能优异:Jackson在序列化和反序列化过程中表现出优秀的性能,通常比其他Java JSON库更快。灵活性:通过注解、自定义序列化器/反序列化器等功能,Jackson提供了丰富的配置选项,允许你根据需求灵活地处理JSON数据。易于使用:Jackson的API设计简洁明了,易于学习和使用。

拜托!别再滥用 ! = null 判空了!!
另外,也许受此习惯影响,他们总潜意识地认为,所有的返回都是不可信任的,为了保护自己程序,就加了大量的判空。如果你养成习惯,都是这样写代码(返回空collections而不返回null),你调用自己写的方法时,就能大胆地忽略判空)这种情况下,null是个”看上去“合理的值,例如,我查询数据库,某个查询条件下,就是没有对应值,此时null算是表达了“空”的概念。最终,项目中会存在大量判空代码,多么丑陋繁冗!,而不要返回null,这样调用侧就能大胆地处理这个返回,例如调用侧拿到返回后,可以直接。

详解Java Math类的toDegrees()方法:将参数从弧度转换为角度
Java Math 类的 toDegrees() 方法是将一个角度的弧度表示转换为其度表示,返回值为double类型,表示从弧度数转换而来的角度数。这就是Java Math 类的 toDegrees() 方法的攻略。我们已经了解了该方法的基本概念、语法、注意事项以及两个示例。希望这篇攻略对你有所帮助。

SpringBoot接口防抖(防重复提交)的一些实现方案
作为一名老码农,在开发后端Java业务系统,包括各种管理后台和小程序等。在这些项目中,我设计过单/多租户体系系统,对接过许多开放平台,也搞过消息中心这类较为复杂的应用,但幸运的是,我至今还没有遇到过线上系统由于代码崩溃导致资损的情况。这其中的原因有三点:一是业务系统本身并不复杂;二是我一直遵循某大厂代码规约,在开发过程中尽可能按规约编写代码;三是经过多年的开发经验积累,我成为了一名熟练工,掌握了一些实用的技巧。啥是防抖所谓防抖,一是防用户手抖,二是防网络抖动。

公司新来一个同事:为什么 HashMap 不能一边遍历一边删除?一下子把我问懵了!
前段时间,同事在代码中KW扫描的时候出现这样一条:上面出现这样的原因是在使用foreach对HashMap进行遍历时,同时进行put赋值操作会有问题,异常ConcurrentModificationException。于是帮同简单的看了一下,印象中集合类在进行遍历时同时进行删除或者添加操作时需要谨慎,一般使用迭代器进行操作。于是告诉同事,应该使用迭代器Iterator来对集合元素进行操作。同事问我为什么?这一下子把我问蒙了?对啊,只是记得这样用不可以,但是好像自己从来没有细究过为什么?