当前位置: 首页 > news >正文

Servlet搭建博客系统

现在我们可以使用Servlet来搭建一个动态(前后端可以交互)的博客系统了(使用Hexo只能实现一个纯静态的网页,即只能在后台自己上传博客)。有一种"多年媳妇熬成婆"的感觉。

一、准备工作

首先创建好项目,引入相关依赖。具体过程在"Servlet的创建"中介绍了。

在这我们要引入servlet,mysql,jackson的相关依赖。

然后将相关web.xml配置好,将网站前端的代码也引入webapp中。

二、业务逻辑的实现

由于数据要进行持久化保存,在这我们使用mysql数据来存储。

首先我们先进行数据库的设计。

在这个博客系统中,会涉及到写博客和登陆的简单操作,因此需要创建两个表:用户表和博客表

因为数据库需要创建,当们换了一台机器的时候需要再一次创建,为了简便,可以将创建的sql语句保存下来,下次直接调用即可。

然后将上述代码复制到mysql的命令行执行即可。


封装数据库

为了简化后续对数据库的crud操作,在这对JDBC进行封装,后续代码就轻松许多了。

在这创建一个dao的文件夹,表示Data Access Object, 即数据访问对象,通过写一些类,然后通过类中的封装好的方法来间接访问数据库。

在dao文件下创建一个DBUtil的类,将连接数据库和释放资源操作进行封装。

package dao;import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class DBUtil {//使用单例模式中的饿汉模式创建实例private static volatile DataSource dataSource = null;private static DataSource getDataSource(){//防止竞争太激烈if(dataSource == null){synchronized (DBUtil.class){if(dataSource == null){dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("root");}}}return dataSource;}//获取数据库连接public static Connection getConnection() {try {return getDataSource().getConnection();} catch (SQLException e) {e.printStackTrace();}return null;}//释放资源public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){//一个一个释放,防止一个抛出异常,后续就不释放连接了if(resultSet != null){try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if(statement != null){try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if(connection != null){try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}

 创建实体类

创建实体类的Dao类,进一步封装数据库操作

package dao;import java.net.ConnectException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;//通过这个类,封装针对 blog 表的增删改查操作
public class BlogDao {//新增一个博客//使用try catch捕获异常,finally释放资源public void insert(Blog blog)  {Connection connection = null;PreparedStatement statement = null;try{connection = DBUtil.getConnection();String sql = "insert into blog values(null, ?, ?, ?, now())";statement = connection.prepareStatement(sql);statement.setString(1, blog.getTitle());statement.setString(2, blog.getContent());statement.setInt(3, blog.getUserId());statement.executeUpdate();}catch (SQLException e){e.printStackTrace();}finally {DBUtil.close(connection, statement, null);}}public List<Blog> getBlogs(){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;List<Blog> blogs = new ArrayList<>();try{connection = DBUtil.getConnection();String sql = "select * from blog";statement = connection.prepareStatement(sql);resultSet = statement.executeQuery();while(resultSet.next()){Blog blog = new Blog();blog.setBlogId(resultSet.getInt("blogId"));blog.setTitle(resultSet.getString("title"));blog.setContent(resultSet.getString("content"));blog.setUserId(resultSet.getInt("userId"));blog.setPostTime(resultSet.getTimestamp("postTime"));blogs.add(blog);}}catch (SQLException e){e.printStackTrace();}finally {DBUtil.close(connection, statement, resultSet);}return blogs;}public Blog getBlog(){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;Blog blog = null;try{connection = DBUtil.getConnection();String sql = "select * from blog";statement = connection.prepareStatement(sql);resultSet = statement.executeQuery();if(resultSet.next()){blog = new Blog();blog.setBlogId(resultSet.getInt("blogId"));blog.setTitle(resultSet.getString("title"));blog.setContent(resultSet.getString("content"));blog.setUserId(resultSet.getInt("userId"));blog.setPostTime(resultSet.getTimestamp("postTime"));}} catch (SQLException e){e.printStackTrace();}finally {DBUtil.close(connection, statement, resultSet);}return blog;}//根据博客ID指定博客删除public void delete(int blogId){Connection connection = null;PreparedStatement statement = null;try{connection = DBUtil.getConnection();String sql = "delete from blog where blogId = ?";statement = connection.prepareStatement(sql);statement.setInt(1, blogId);statement.executeUpdate();}catch (SQLException e){e.printStackTrace();}finally {DBUtil.close(connection, statement, null);}}
}

后面再处理数据库操作的时候就可以直接使用这些代码了。

通过观察这些代码,我们会发现非常多重复的东西,后期通过学习了一些高级的框架后就能将代码的结构再优化一下.

同理,UserDao类也是如此完成。

至此,数据方面的东西我们都已经写完了,后续只需要调用即可。

接来下就可以进行一些前后端交互逻辑的实现了。

在这以功能点为维度进行展开,针对每个功能点,进行"设计前后端交互接口","开发后端代码","开发前端代码","调试"

实现博客列表页

让博客列表页能够加载博客列表。

大致流程如下:

  1. 前端发起一个HTTP请求,向后端所要博客列表数据

  2. 后端收到请求之后查询数据库获取数据库中的 博客列表,将数据返回给前端

  3. 前端拿到响应后,根据内容构造出html片段,并显示。

在写代码前,需要进行约定,即规范双方发什么样的数据,发什么请求,如何解析数据等。

假设双方约定按照如下格式发送数据。

后端代码:

@WebServlet("/html/blog")
public class BlogServlet extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//从数据库中获取数据BlogDao blogDao = new BlogDao();List<Blog> blogs = blogDao.getBlogs();//将数组转换成对象字符串String respJson = objectMapper.writeValueAsString(blogs);resp.setContentType("application/json; charset=utf8");//写回到响应中resp.getWriter().write(respJson);}
}

前端代码:

让页面通过js的ajax的方式发起http请求。

 function getBlogs(){$.ajax({type: 'get',url: 'blog',success: function(body){let container = document.querySelector('.container-right');for(let blog of body){let blogDiv = document.createElement('div');blogDiv.className='blog';//构造标题let titleDiv = document.createElement('div');titleDiv.className = 'title';titleDiv.innerHTML = blog.title;blogDiv.appendChild(titleDiv);//构造发布时间let dateDiv = document.createElement('div');dateDiv.className = 'date';dateDiv.innerHTML = blog.postTime;blogDiv.appendChild(dateDiv);//构造博客摘要let descDiv = document.createElement('div');descDiv.className = 'desc';descDiv.innerHTML = blog.content;blogDiv.appendChild(descDiv);//构造查看全文按钮let a = document.createElement('a');a.href = 'blog_content.html?blogId=' + blog.blogId;a.innerHTML = '查看全文 &gt;&gt';blogDiv.appendChild(a);container.appendChild(blogDiv);}}});}getBlogs();

由于数据库中的数据为标明啥数据,我们还需要手动指定.

效果如下:

博客详情页

1.约定前后端交互接口

和前面博客列表页类似,不同的是我们只需要在请求中带上blogId的属性,以及后端代码的稍作修改即可。

后端代码:

我们可以通过对之前的后端代码稍作修改,就可以完成上述操作。

前端代码:

 <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>function getBlog(){$.ajax({type: 'get',url: 'blog'+location.search,success: function(body){let h3 = document.querySelector('.container-right h3');h3.innerHTML = body.title;let dateDiv = document.querySelector('.container-right .date');dateDiv.innerHTML = body.postTime;editormd.markdownToHTML('content', { markdown: body.content });}});}getBlog();</script>

登录功能

1.约定前后端交互接口

此处提交用户名和密码,可以使用form也可以使用ajax。在这使用form的形式(更简单一些)。

2.后端代码

@WebServlet("/html/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//首先获取请求中的查询字符串中的用户名和密码//需要手动告诉Servlet,使用什么样的编码方式来读取请求req.setCharacterEncoding("utf8");String username = req.getParameter("username");String password = req.getParameter("password");if(username == null || password == null || username.equals("") || password.equals("")){//用户提交的数据非法resp.setContentType("text/html; charset=utf8");resp.getWriter().write("当前的用户名或密码非法");return;}//再去数据库中比对UserDao userDao = new UserDao();User user = userDao.getUserByName(username);if(user == null){resp.setContentType("text/html; charset=utf8");resp.getWriter().write("当前的用户名或密码错误");return;}if(!user.getPassword().equals(password)){resp.setContentType("text/html; charset=utf8");resp.getWriter().write("当前的用户名或密码错误");}//创建会话关系HttpSession session = req.getSession(true);session.setAttribute("user", user);//发送重定向网页,跳转到列表页resp.sendRedirect("blog_list.html");}
}

注意:

由于请求中可能带有中文字符,我们需要手动指定一下字符集utf8,防止读取请求的时候出现乱码。

使用一个会话,让服务器保存当前用户的一些数据。

3.前端代码

            <form action="login" method="post"><div class="row"><span>用户名</span><input type="text" id="username"></div><div class="row"><span>密码</span><input type="password" id="password"></div><div class="row"><input type="submit" id="submit" value="登录"></div></form>

检查用户登录状态

强制用户登录,当用户直接去访问博客列表页或者其他页面的时候,如果是未登录过的状态,会强制跳转到登录页要求用户登录。

如何实现?

在其他页面中的前端代码,写一个ajax请求,通过这个请求,访问服务器来获取当前的登录状态。

如果当前未登录,则跳转登录页面,如果已经登录,就不进行操作。

1.约定前后端交互接口

2.后端代码

   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession(false);if(session == null){resp.setStatus(403);return;}User user = (User) session.getAttribute("user");if(user == null){resp.setStatus(403);return;}resp.setStatus(200);}

3.前端代码

<div class="login-container"><!-- 登录对话框 --><div class="login-dialog"><h3>登录</h3><!-- 使用 form 包裹一下下列内容, 便于后续给服务器提交数据 --><form action="login" method="post"><div class="row"><span>用户名</span><input type="text" id="username" name="username"></div><div class="row"><span>密码</span><input type="password" id="password" name="password"></div><div class="row"><input type="submit" id="submit" value="登录"></div></form></div></div>

form表单中的action为请求中的url,method为请求中的方法类型,id属性时针对html获取元素,name属性则是针对form表单构造http请求。

显示用户信息

当我们进入博客列表页的时候,用户显示的内容应该是登录用户的信息,一旦我们进入到博客详情页的时候,显示的就应该是该博客作者的信息。

首先是博客列表页

1.约定前后端交互接口

2.后端代码

由于我们进入博客列表页,首先会去检查是否已经登录过,如果登录过就可以拿到用户的数据,此时我们可以将用户数据返回给前端,然后修改用户姓名的属性。此时我们也只要在前面代码的基础上稍加修改。

        //防止将密码传输回去user.setPassword("");String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);

3.前端代码

前端代码也只需要在之前的基础上稍加修改就行

function checkLogin(){$.ajax({type: 'get',url: 'login',success: function(body){let h3 = document.querySelector('h3');h3.innerHTML = body.username;},error: function(body){location.assign('blog_login.html');}}) ;
}

然后是博客详情页

详情页这里显示的是当前文章的作者信息,由于我们知道blogId,就可以查询到userId然后就能查询到user的信息。最后再将信息显示出来即可。

1.约定前后端交互接口

2.后端代码

public class UserServlet extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String blogId = req.getParameter("blogId");//如果用户直接访问博客详情页if(blogId == null){//从session中拿到user对象HttpSession session = req.getSession(false);if(session == null){//为了方便后续统一处理,返回空对象User user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);return;}User user = (User)session.getAttribute("user");String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}else{BlogDao blogDao = new BlogDao();Blog blog = blogDao.getBlog(Integer.parseInt(blogId));if(blog == null){User user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);return;}UserDao userDao = new UserDao();User user = userDao.getUserById(blog.getUserId());if(user == null){String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);return;}String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}}
}

3.前端代码

前端代码前面博客列表页类似

        function getUser(){$.ajax({type:'get',url:'user'+location.search,success: function(body){let h3 = document.querySelector('.card h3');h3.innerHTML = body.username;}});}getUser();

用户退出功能

当用户点击注销的时候,即点击了a标签,此时会触发一个get请求,服务器收到这个get请求,就可以把当前用户会话中的user对象删除。即通过代码删除之前的session对象(最好是删除映射关系,但是Servlet没有提供相应简单的API).

1.约定前后端交互接口

2.后端代码

@WebServlet("/html/logout")
public class LogoutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession(false);if(session == null){resp.sendRedirect("blog_login.html");return;}session.removeAttribute("user");resp.sendRedirect("blog_login.html");}
}

3.前端代码

只需要给a元素写个href即可。

发布博客

在写博客页中,用户可以写博客标题,正文,然后点击发布即可上传数据。

1.约定前后端交互接口

2.后端代码

 @Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession(false);if(session == null){resp.setContentType("text/html; charset=utf8");resp.getWriter().write("用户未登录! 无法发布博客!");return;}User user = (User)session.getAttribute("user");if (user == null) {resp.setContentType("text/html; charset=utf8");resp.getWriter().write("用户未登录! 无法发布博客!");return;}resp.setCharacterEncoding("utf8");String title = req.getParameter("title");String content = req.getParameter("content");if (title == null || content == null || "".equals(title) || "".equals(content)) {resp.setContentType("text/html; charset=utf8");resp.getWriter().write("标题或者正文为空");return;}Blog blog = new Blog();blog.setTitle(title);blog.setContent(content);blog.setUserId(user.getUserId());BlogDao blogDao = new BlogDao();blogDao.insert(blog);resp.sendRedirect("blog_list.html");}

3.前端代码

    <div class="blog-edit-container"><form action="blog" method="post"><!-- 标题编辑区 --><div class="title"><input type="text" id="title-input" name="title"><input type="submit" id="submit"></div><!-- 博客编辑器 --><!-- 把 md 编辑器放到这个 div 中 --><div id="editor"><textarea name="content" style="display: none;"></textarea></div></form></div>

相关文章:

Servlet搭建博客系统

现在我们可以使用Servlet来搭建一个动态(前后端可以交互)的博客系统了(使用Hexo只能实现一个纯静态的网页,即只能在后台自己上传博客)。有一种"多年媳妇熬成婆"的感觉。 一、准备工作 首先创建好项目,引入相关依赖。具体过程在"Servlet的创建"中介绍了。…...

NextJs 渲染篇 - 什么是CSR、SSR、SSG、ISR 和服务端/客户端组件

NextJs 渲染篇 - 什么是CSR、SSR、SSG、ISR 和服务端/客户端组件 前言一. 什么是CSR、SSR、SSG、ISR1.1 CSR 客户端渲染1.2 SSR 服务端渲染1.3 SSG 静态站点生成① 没有数据请求的页面② 页面内容需要请求数据③ 页面路径需要获取数据 1.4 ISR 增量静态再生1.5 四种渲染方式的对…...

Python 二叉数的实例化及遍历

首先创建一个这样的二叉树&#xff0c;作为我们今天的实例。实例代码在下方。 #创建1个树类型 class TreeNode:def __init__(self,val,leftNone,rightNone):self.valvalself.leftleftself.rightright #实例化类 node1TreeNode(5) node2TreeNode(6) node3TreeNode(7) node4Tre…...

计算 x 的二进制表示中 1 的个数

计算 x 的二进制表示中 1 的个数 代码如下&#xff1a; int func(int x){int countx 0;while (x>0){countx;x x & (x - 1);}return countx;} 完整代码&#xff1a; using System; using System.Collections.Generic; using System.ComponentModel; using System.Dat…...

基于Vue的前端瀑布流布局组件的设计与实现

摘要 随着前端技术的不断演进&#xff0c;复杂业务场景和多次迭代后的产品对组件化开发提出了更高的要求。传统的整块应用开发方式已无法满足快速迭代和高效维护的需求。因此&#xff0c;本文将介绍一款基于Vue的瀑布流布局组件&#xff0c;旨在通过组件化开发提升开发效率和降…...

WinSW使用说明

WinSW使用说明 Windows系统下部署多个java程序 场景&#xff1a; 多个java的jar程序&#xff0c;通常来说一个程序使用一个cmd窗口&#xff0c;通过java -jar xxx.jar 命令来运行。这样如果程序多了打开cmd窗口也就多了。 解决&#xff1a; 通过使用WinSW程序&#xff0c;把ja…...

SpringBoot 多模块 多环境 项目 单元测试

环境描述 假设项目中有以下三个yml文件&#xff1a; application.ymlapplication-dev.ymlapplication-prod.yml 假设项目各Module之间依赖关系如下&#xff1a; 其中&#xff0c;D依赖C&#xff0c;C依赖B&#xff0c;B依赖A&#xff0c;D对外提供最终的访问接口 现在要想采…...

网络安全法中的网络安全规定和措施

《中华人民共和国网络安全法》是中国首部全面规范网络空间安全管理的基础性法律&#xff0c;旨在加强网络安全&#xff0c;保障国家安全和社会公共利益&#xff0c;保护公民、法人和其他组织的合法权益&#xff0c;促进互联网的健康发展。以下是该法律中关于网络安全的一些核心…...

一、搭建 Vue3 Admin 项目:从无到有的精彩历程

在前端开发的领域中&#xff0c;Vue3 展现出了强大的魅力&#xff0c;而搭建一个功能丰富的 Vue3 Admin 项目更是充满挑战与乐趣。今天&#xff0c;我将和大家分享我搭建 Vue3 Admin 项目的详细过程&#xff0c;其中用到了一系列重要的依赖包。 首先 让我们开启这个旅程。在确…...

Qt | Qt 资源简介(rcc、qmake)

1、资源系统是一种独立于平台的机制,用于在应用程序的可执行文件中存储二进制文件(前面所讨论的数据都存储在外部设备中)。若应用程序始终需要一组特定的文件(比如图标),则非常有用。 2、资源系统基于 qmake,rcc(Qt 的资源编译器,用于把资源转换为 C++代码)和 QFile …...

对boot项目拆分成cloud项目的笔记

引言&#xff1a;这里我用的是新版本的技术栈 spring-boot-starter-parent >3.2.5 mybatis-spring-boot-starter >3.0.3 mybatis-plus-boot-starter >3.5.5 spring-cloud-dependencies …...

CTF本地靶场搭建——基于阿里云ACR实现动态flag题型的创建

接上文&#xff0c;这篇主要是结合阿里云ACR来实现动态flag题型的创建。 这里顺便也介绍一下阿里云的ACR服务。 阿里云容器镜像服务&#xff08;简称 ACR&#xff09;是面向容器镜像、Helm Chart 等符合 OCI 标准的云原生制品安全托管及高效分发平台。 ACR 支持全球同步加速、…...

【面试经典150题】删除有序数组中的重复项

目录 一.删除有序数组中的重复项 一.删除有序数组中的重复项 题目如上图所示&#xff0c;这里非严格递增排序的定义是数字序列&#xff0c;其中相邻的数字可以相等&#xff0c;并且数字之间的差值为1。 这题我们依旧使用迭代器进行遍历&#xff0c;比较当前的数据是否与下一个数…...

太阳能辐射整车综合性能环境试验舱

产品别名 步入式恒温恒湿试验箱、步入式温湿度试验箱、温度试验室、模拟环境试验室、大型恒温恒湿箱、步入式高低温湿热交变试验箱、大型高低温箱、步入式老化箱、恒温恒湿试验房、步入式高低温试验箱. 整车综合性能环境试验舱:整车综合性能环境试验舱:主要用于整车高低温存放…...

JS脚本打包成一个 Chrome 扩展(CRX 插件)

受这篇博客 如何把CSDN的文章导出为PDF_csdn文章怎么导出-CSDN博客 启发&#xff0c;将 JavaScript 代码打包成一个 Chrome 扩展&#xff08;CRX 插件&#xff09;。 步骤&#xff1a; 1.创建必要的文件结构和文件&#xff1a; manifest.jsonbackground.jscontent.js 2.编写…...

js事件对象

js事件对象概念说明 在JavaScript中&#xff0c;事件对象是在事件触发时由浏览器自动创建的一个对象。它包含了与事件相关的信息&#xff0c;例如触发事件的元素、事件类型、鼠标的坐标等。 可以通过事件处理函数的第一个参数来访问事件对象。例如&#xff0c;在一个鼠标点击…...

希捷硬盘怎么恢复数据? 5 个免费希捷数据恢复软件

希捷已迅速成为全球最大的数字存储提供商。许多人选择并使用希捷外置硬盘来存储他们的媒体文件、学校或工作文件以及其他重要数据。有时&#xff0c;希捷硬盘中的数据会丢失。 如果您丢失了希捷硬盘上的数据&#xff0c;请不要惊慌。在专业的希捷数据恢复软件的帮助下&#xf…...

Nvidia Jetson/Orin +FPGA+AI大算力边缘计算盒子:京东无人配送机器人

电商巨头京东已选用NVIDIA Jetson AGX Xavier 平台&#xff0c;作为下一代自主配送机器人核心AI算力。 在过去的几十年中&#xff0c;中国占据了全球40&#xff05;以上的电商交易——每年约为千亿美元。根据麦肯锡全球研究院的数据&#xff0c;这一数字已经高于法国、德国、…...

STM32作业实现(七)OLED显示数据

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…...

elementui el-tooltip文字提示组件弹出层内容格式换行处理

1、第一种 1.1 效果图 1.2、代码 <template><div class"wrapper"><el-tooltip class"content" effect"dark" placement"top"><div slot"content"><div v-html"getTextBrStr(text)"&…...

IT运维监控/可观测性

?? 前言&#xff1a;为什么选择 OpenClaw 对接企业微信&#xff1f; 在2026年的企业数字化办公浪潮中&#xff0c;OpenClaw&#xff08;曾用名 Clawdbot、Moltbot&#xff09;已成长为国内领先的开源AI自动化代理工具。凭借其“自然语言驱动、插件化拓展、多平台无缝集成”的…...

探索前沿技术趋势:2024年最值得关注的创新应用场景

1. 生成式AI的爆发式应用 2024年最让人兴奋的技术趋势&#xff0c;莫过于生成式AI从实验室走向千家万户。我最近测试了十几个主流AI创作工具&#xff0c;发现它们已经能完成许多过去认为"只有人类能做到"的任务。比如用Midjourney生成产品设计图&#xff0c;只需要简…...

IP5306电源芯片的‘怪脾气’:实测开机半分钟就休眠?手把手教你两个硬件调试技巧

IP5306电源芯片实战调试&#xff1a;破解自动休眠难题的硬件级方案 实验室里&#xff0c;示波器屏幕上那条本该稳定的电压线突然跌落至零&#xff0c;系统再次陷入休眠——这已经是今天第七次重现IP5306芯片的"怪脾气"。作为一款广泛应用于移动电源的高集成度SOC&…...

DBA_RECYCLEBIN purge指定日期前的表

SummaryHow to purge DBA_RECYCLBIN for objects older than x days/minutes? or do we have RECYCLEBIN RETENTION feature or truncate recyclebin ?--------------------------------------------------------------------------------------DBA_RECYCLEBIN has a column …...

python-flask-djangol框架的膳食营养食谱管理系统

目录需求分析技术选型数据库设计核心功能实现界面设计测试与部署维护与扩展项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作需求分析 膳食营养食谱管理系统需要具备用户管理、食谱管理、营养分析、购物清单生成等功能。系统应支…...

STM32串口通信原理与实现详解

串口通信技术深度解析&#xff1a;从原理到STM32实现1. 串口通信基础概念1.1 数据传送方向分类串行通信根据数据传输方向可分为三种基本模式&#xff1a;单工模式&#xff1a;数据仅支持单向传输&#xff0c;如传统的广播系统。发送端和接收端角色固定&#xff0c;硬件上只需单…...

MarkDownload:让网页转Markdown变得简单高效的浏览器扩展

MarkDownload&#xff1a;让网页转Markdown变得简单高效的浏览器扩展 【免费下载链接】markdownload A Firefox and Google Chrome extension to clip websites and download them into a readable markdown file. 项目地址: https://gitcode.com/gh_mirrors/ma/markdownload…...

不止于公式:用国民技术N32G45x定时器实现精准时间片调度(附代码)

不止于公式&#xff1a;用国民技术N32G45x定时器实现精准时间片调度&#xff08;附代码&#xff09; 在嵌入式系统开发中&#xff0c;定时器是最基础也最强大的外设之一。对于国民技术N32G45x系列微控制器而言&#xff0c;其丰富的定时器资源&#xff08;TIM2/3/4等&#xff09…...

5个维度掌握wechat-api:从入门到生产的微信机器人开发指南

5个维度掌握wechat-api&#xff1a;从入门到生产的微信机器人开发指南 【免费下载链接】wechat-api &#x1f5ef; wechat-api by java7. 项目地址: https://gitcode.com/gh_mirrors/we/wechat-api 核心价值&#xff1a;企业为什么需要微信机器人&#xff1f; 在数字化…...

【SOC】Fastboot /DFU 烧录镜像

uboot下 使用fastboot 进行 UFS/EMMC/nand 设备烧录的大致流程&#xff1a; board 进入 uboot&#xff08;支持 fastboot&#xff09;&#xff1b; 同时host机器安装上 fastboot 客户端 ; 2者&#xff08;board与host&#xff09;之间通过usb线连接,通过fastboot 协议进行交互…...