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

MVC模式分层练习

新建库

新建表

插入点数据

先不用MVC模式写功能,来看下缺点是什么

新建一个空项目

选项项目使用的JDK

自己的IDEA总是要重启下

新建模块

因maven还没教

添加框架支持

添加后项目多了这些

添加些必要依赖  这里注意下,如果导入jar包不对可以重新导入下或者是jar包本身出了问题

添加页面

配置Tomcat

启动

请求地址  因现在没有后端

现在写后端 并测试

解决控制台输出乱码问题

System.out输出乱码

需要用到JDBC连接Mysql数据库

导入Mysql驱动jar包

java web项目  一般会在WEB-INF下有个lib用来放Tomcat内没有,外部引入的依赖

可以创建个lib目录  然后将jar包复制进来

具体代码

package com.bank.web;import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.sql.*;
import java.util.Locale;/*** 在不使用MVC架构模式的前提下,完成银行账户转账* 分析这个程序存在哪些问题?* @author hrui* @date 2023/8/31 23:06*/
@WebServlet("/transfer")
public class AccountTransferServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取响应流对象resp.setContentType("text/html;charset=UTF-8");PrintWriter writer = resp.getWriter();//获取前端传来的参数String fromActno = req.getParameter("fromActno");String toActno = req.getParameter("toActno");double money = Double.parseDouble(req.getParameter("money"));
//        System.out.println("转出账户:"+fromActno);
//        System.out.println("转入账户:"+fromActno);
//        System.out.println("转账金额:"+fromActno);//编写转账的业务逻辑代码,连接数据库,进行转账操作//1.转账之前要判断转出账户的余额是否充足Connection conn=null;PreparedStatement ps=null;//PreparedStatement ps2=null;ResultSet rs=null;try {//注册驱动Class.forName("com.mysql.cj.jdbc.Driver");//获取连接conn = DriverManager.getConnection("xxx", "xxx", "xxx");conn.setAutoCommit(false);//获取执行对象String sql="select balance from t_act where actno=?";ps = conn.prepareStatement(sql);ps.setString(1, fromActno);//执行sql,返回结果集rs = ps.executeQuery();//获取结果集if(rs.next()){double balance = rs.getDouble("balance");if(balance<money){//余额不足(使用异常处理机制)throw new MoneyNotEnoughException("余额不足");}//程序能到这里,说明余额重组  不需要else//开始转账sql="update t_act set balance=balance-? where actno=?";ps = conn.prepareStatement(sql);ps.setDouble(1, money);ps.setString(2, fromActno);int count = ps.executeUpdate();//模拟异常String str=null;str.toString();sql="update t_act set balance=balance+? where actno=?";ps=conn.prepareStatement(sql);ps.setDouble(1, money);ps.setString(2, toActno);//累计count += ps.executeUpdate();if(count!=2){throw new AppException("app异常,请联系管理员");}}conn.commit();writer.print("转账成功");} catch (ClassNotFoundException | SQLException | MoneyNotEnoughException | AppException e) {try {if(conn!=null) {conn.rollback();}} catch (SQLException e1) {e1.printStackTrace();}e.printStackTrace();writer.print(e.getMessage());}finally {//释放资源,根据JDBC规范 从小到大if(rs!=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if(ps!=null){try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if(conn!=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

1>负责了数据接收

2>负责了核心业务处理

3>负责了数据库表中的CRUD操作(Create(增) Retrieve(查) Update(改) Delete(删))

4>负责了数据的页面展示

引起的缺点:

代码复用性差  比如查余额,可以抽取出来,单独放到一个方法

代码复用性差的原因,没有职能分工,独立组件的概念,代码之间耦合度高,扩展力差

操作数据库代码和业务逻辑混杂在一起,容易出错,无法专注于业务逻辑书写

下面以MVC的模式对上面代码改进

1.系统为什么要分层?

        希望专人干专事.各司其职.分工明确.这样可以降低耦合,扩展增强.复用增强

2.软件架构中,有一个非常著名的架构模式:MVC模式

M(Model:数据/业务)       V(View:视图/展示)       C(Controller:控制器/核心)

首先是对JDBC的封装

JDBC工具类

package com.bank.utils;import java.sql.*;
import java.util.ResourceBundle;/*** @author hrui* @date 2023/9/1 10:24*/
public class DBUtil {private static ResourceBundle bundle=ResourceBundle.getBundle("resources/jdbc");private static String driver=bundle.getString("driver");private static String url=bundle.getString("url");private static String username=bundle.getString("username");private static String password=bundle.getString("password");//不让创建对象,原因工具类方法一般都静态的,无需外部创建对象//为防止外部创建对象,构造私有化private DBUtil(){}//DBUtil类加载时注册驱动static{try {Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}//没有使用连接池,直接创建的连接对象public static Connection getConnection() throws SQLException {Connection conn= DriverManager.getConnection(url,username,password);return conn;}public static void close(Connection conn, Statement statement, ResultSet rs){if(rs!=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if(statement!=null){try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if(conn!=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}

测试连接

封装实体类

package com.bank.mvc;import java.util.Objects;/*** 账户实体类,用于封装账户信息* POJO对象* 有的人也会把这种专门封装数据的对象,称为bean对象(javabean:咖啡豆)* 有的人也会把这种专门分装数据的对象,称为领域模型对象.domain对象.* pojo,bean,domain* @author hrui* @date 2023/9/1 15:34*/
public class Account {private Long id;private String actno;private Double balance;public Account() {}public Account(Long id, String actno, Double balance) {this.id = id;this.actno = actno;this.balance = balance;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getActno() {return actno;}public void setActno(String actno) {this.actno = actno;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Account acount = (Account) o;return id.equals(acount.id) && actno.equals(acount.actno) && balance.equals(acount.balance);}@Overridepublic int hashCode() {return Objects.hash(id, actno, balance);}@Overridepublic String toString() {return "Account{" +"id=" + id +", actno='" + actno + '\'' +", balance=" + balance +'}';}
}

编写DAO层

package com.bank.mvc;import com.bank.utils.DBUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;/*** 负责Acount数据的增删改查* 1.什么是DAO*      Data Access Object(数据访问对象)* 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)* 3.DAO只负责数据库CRUD,没有任何业务逻辑* 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象* @author hrui* @date 2023/9/1 12:39*/
public class AccountDao {public int insert(Account act){Connection conn=null;PreparedStatement ps=null;int count=0;try {conn= DBUtil.getConnection();String sql="insert into t_act(actno,balance) values (?,?)";ps=conn.prepareStatement(sql);ps.setString(1, act.getActno());ps.setDouble(2, act.getBalance());count=ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(conn,ps,null);}return count;}public int deleteByActno(Long id){Connection conn=null;PreparedStatement ps=null;int count=0;try {conn=DBUtil.getConnection();String sql="delete from t_act where id=?";ps=conn.prepareStatement(sql);ps.setLong(1, id);count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(conn,ps,null);}return count;}public int update(Account act){Connection conn=null;PreparedStatement ps=null;int count=0;try {conn=DBUtil.getConnection();String sql="update t_act set balance=? where id=?";ps=conn.prepareStatement(sql);ps.setDouble(1, act.getBalance());ps.setLong(2, act.getId());count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(conn,ps,null);}return count;}public Account selectBtActNo(String actno){Connection conn=null;PreparedStatement ps=null;ResultSet rs=null;Account account=new Account();try {conn=DBUtil.getConnection();String sql="select id,actno,balance from t_act where actno=?";ps=conn.prepareStatement(sql);ps.setString(1, actno);rs = ps.executeQuery();if(rs.next()){Long id=rs.getLong("id");String actno1=rs.getString("actno");Double balance=rs.getDouble("balance");account.setId(id);account.setActno(actno1);account.setBalance(balance);}} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(conn,ps,null);}return account;}public List<Account> selectAll(){Connection conn=null;PreparedStatement ps=null;ResultSet rs=null;List<Account> list=new ArrayList<>();try {conn=DBUtil.getConnection();String sql="select id,actno,balance from t_act ";ps=conn.prepareStatement(sql);rs = ps.executeQuery();while(rs.next()){Long id=rs.getLong("id");String actno=rs.getString("actno");Double balance=rs.getDouble("balance");Account account=new Account();account.setId(id);account.setActno(actno);account.setBalance(balance);list.add(account);}} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(conn,ps,null);}return list;}
}

原先在Servlet里

1>负责了数据接收

2>负责了狠心业务处理

3>负责了数据库表中数据CRUD操作

4>负责了页面数据展示

现在已经一层层分离了

两个异常类

用AccountSAervice来做业务处理

具体业务处理代码

package com.bank.mvc;import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;/*** Service:业务* 专门处理Account的业务处理类* 该类只专注业务处理* 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以* @author hrui* @date 2023/9/2 0:49*/
public class AccountService {private AccountDao accountDao=new AccountDao();/*** 完成转账的业务逻辑* @param fromActno* @param toActno* @param money*/public void transfer(String fromActno,String toActno,double money) throws MoneyNotEnoughException, AppException {//查询余额是否充足Account fromAccount = accountDao.selectBtActNo(fromActno);if(fromAccount.getBalance()<money){throw new MoneyNotEnoughException("余额不足");}//程序到这里说明余额够Account toAct=accountDao.selectBtActNo(toActno);//修改余额fromAccount.setBalance(fromAccount.getBalance()-money);toAct.setBalance(toAct.getBalance()+money);//更新数据库int count=accountDao.update(fromAccount);count += accountDao.update(toAct);//count++;if(count!=2){throw new AppException("转账异常");}}}

servlet里做的就是调度

package com.bank.mvc;import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** 让AcountServlet做为Controller  调度员* 负责调度其他组件* @author hrui* @date 2023/9/1 12:27*/
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取前端传来的参数String fromActno = req.getParameter("fromActno");String toActno = req.getParameter("toActno");double money = Double.parseDouble(req.getParameter("money"));//调用业务方法处理业务(调度Model处理业务)AccountService accountService=new AccountService();try {accountService.transfer(fromActno,toActno,money);resp.sendRedirect(req.getContextPath()+"/success.jsp");} catch (MoneyNotEnoughException e) {e.printStackTrace();resp.sendRedirect(req.getContextPath()+"/moneynoenough.jsp");} catch (AppException e) {e.printStackTrace();resp.sendRedirect(req.getContextPath()+"/error.jsp");}}
}

三个页面显示

 

上面代码缺少事务控制,一般事务都在service进行控制

一般来说是在service层去开启事务  提交事务

这里事务管理,做的low的方式就是在业务层获取数据库连接对象,然后传进去,当然这样做的话,在DAO层就不要在finally中关闭事务了.传个null就行,在Service中开启事务,并在Service中提交事务,在Service中的finally中关闭连接

上代码

DAO

package com.bank.mvc;import com.bank.utils.DBUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;/*** 负责Acount数据的增删改查* 1.什么是DAO*      Data Access Object(数据访问对象)* 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)* 3.DAO只负责数据库CRUD,没有任何业务逻辑* 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象* @author hrui* @date 2023/9/1 12:39*/
public class AccountDao {public int insert(Account act,Connection conn){PreparedStatement ps=null;int count=0;try {String sql="insert into t_act(actno,balance) values (?,?)";ps=conn.prepareStatement(sql);ps.setString(1, act.getActno());ps.setDouble(2, act.getBalance());count=ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return count;}public int deleteByActno(Long id,Connection conn){PreparedStatement ps=null;int count=0;try {String sql="delete from t_act where id=?";ps=conn.prepareStatement(sql);ps.setLong(1, id);count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return count;}public int update(Account act,Connection conn){PreparedStatement ps=null;int count=0;try {String sql="update t_act set balance=? where id=?";ps=conn.prepareStatement(sql);ps.setDouble(1, act.getBalance());ps.setLong(2, act.getId());count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return count;}public Account selectBtActNo(String actno,Connection conn){PreparedStatement ps=null;ResultSet rs=null;Account account=new Account();try {String sql="select id,actno,balance from t_act where actno=?";ps=conn.prepareStatement(sql);ps.setString(1, actno);rs = ps.executeQuery();if(rs.next()){Long id=rs.getLong("id");String actno1=rs.getString("actno");Double balance=rs.getDouble("balance");account.setId(id);account.setActno(actno1);account.setBalance(balance);}} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return account;}public List<Account> selectAll(Connection conn){Connection conn=null;PreparedStatement ps=null;ResultSet rs=null;List<Account> list=new ArrayList<>();try {String sql="select id,actno,balance from t_act ";ps=conn.prepareStatement(sql);rs = ps.executeQuery();while(rs.next()){Long id=rs.getLong("id");String actno=rs.getString("actno");Double balance=rs.getDouble("balance");Account account=new Account();account.setId(id);account.setActno(actno);account.setBalance(balance);list.add(account);}} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return list;}
}

Service

package com.bank.mvc;import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;
import com.bank.utils.DBUtil;import java.sql.Connection;
import java.sql.SQLException;/*** Service:业务* 专门处理Account的业务处理类* 该类只专注业务处理* 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以* @author hrui* @date 2023/9/2 0:49*/
public class AccountService {private AccountDao accountDao=new AccountDao();/*** 完成转账的业务逻辑* @param fromActno* @param toActno* @param money*/public void transfer(String fromActno,String toActno,double money) throws MoneyNotEnoughException, AppException {//Service层控制事务//开启事务(需要用到Connection对象)Connection conn=null;try {conn = DBUtil.getConnection();conn.setAutoCommit(false);//查询余额是否充足Account fromAccount = accountDao.selectBtActNo(fromActno,conn);if(fromAccount.getBalance()<money){throw new MoneyNotEnoughException("余额不足");}//程序到这里说明余额够Account toAct=accountDao.selectBtActNo(toActno,conn);//修改余额fromAccount.setBalance(fromAccount.getBalance()-money);toAct.setBalance(toAct.getBalance()+money);//更新数据库int count=accountDao.update(fromAccount,conn);count += accountDao.update(toAct,conn);
//        String str=null;
//        str.toString();//或者//count++;  会向用户提示转账失败  但是转账确已经完成   或者1账户减款而2账户没有加的情况if(count!=2){throw new AppException("转账异常");}conn.commit();} catch (SQLException e) {e.printStackTrace();}finally {DBUtil.close(conn,null,null);}}}

 

但上面代码有点low

如何解决Connection传参问题

用ThreadLocal

改造代码

DBUtil

package com.bank.utils;import java.sql.*;
import java.util.ResourceBundle;/*** @author hrui* @date 2023/9/1 10:24*/
public class DBUtil {private static ResourceBundle bundle=ResourceBundle.getBundle("resources/jdbc");private static String driver=bundle.getString("driver");private static String url=bundle.getString("url");private static String username=bundle.getString("username");private static String password=bundle.getString("password");//不让创建对象,原因工具类方法一般都静态的,无需外部创建对象//为防止外部创建对象,构造私有化private DBUtil(){}//DBUtil类加载时注册驱动static{try {Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}private static ThreadLocal<Connection> local=new ThreadLocal<>();//没有使用连接池,直接创建的连接对象public static Connection getConnection() throws SQLException {Connection conn=local.get();if(conn==null) {conn = DriverManager.getConnection(url, username, password);local.set(conn);}return conn;}public static void close(Connection conn, Statement statement, ResultSet rs){if(rs!=null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if(statement!=null){try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if(conn!=null){try {conn.close();//注意:关闭连接时候移除  Tomcat是支持线程池的,不从当前线程里移除 有可能下次别人拿到了,但是conn已经关闭local.remove();} catch (SQLException e) {e.printStackTrace();}}}
}

将AccountDao恢复原状,还是从DBUtil里取Connection,但是不需要再传参数,注意finally里面Connection照样传null,原因:还是需要在Service层进行事务控制

package com.bank.mvc;import com.bank.utils.DBUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;/*** 负责Acount数据的增删改查* 1.什么是DAO*      Data Access Object(数据访问对象)* 2.DAO实际上是一种设计模式,属于JAVAEE的设计模式之一.(不是23种设计模式)* 3.DAO只负责数据库CRUD,没有任何业务逻辑* 4.没有任何业务逻辑,只负责表中数据增删改查,有一个特殊的称谓:DAO对象* @author hrui* @date 2023/9/1 12:39*/
public class AccountDao {public int insert(Account act){PreparedStatement ps=null;int count=0;try {Connection  conn= DBUtil.getConnection();String sql="insert into t_act(actno,balance) values (?,?)";ps=conn.prepareStatement(sql);ps.setString(1, act.getActno());ps.setDouble(2, act.getBalance());count=ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return count;}public int deleteByActno(Long id){PreparedStatement ps=null;int count=0;try {Connection  conn= DBUtil.getConnection();String sql="delete from t_act where id=?";ps=conn.prepareStatement(sql);ps.setLong(1, id);count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return count;}public int update(Account act){PreparedStatement ps=null;int count=0;try {Connection conn=DBUtil.getConnection();String sql="update t_act set balance=? where id=?";ps=conn.prepareStatement(sql);ps.setDouble(1, act.getBalance());ps.setLong(2, act.getId());count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return count;}public Account selectBtActNo(String actno){PreparedStatement ps=null;ResultSet rs=null;Account account=new Account();try {Connection conn=DBUtil.getConnection();String sql="select id,actno,balance from t_act where actno=?";ps=conn.prepareStatement(sql);ps.setString(1, actno);rs = ps.executeQuery();if(rs.next()){Long id=rs.getLong("id");String actno1=rs.getString("actno");Double balance=rs.getDouble("balance");account.setId(id);account.setActno(actno1);account.setBalance(balance);}} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return account;}public List<Account> selectAll(){PreparedStatement ps=null;ResultSet rs=null;List<Account> list=new ArrayList<>();try {Connection conn=DBUtil.getConnection();String sql="select id,actno,balance from t_act ";ps=conn.prepareStatement(sql);rs = ps.executeQuery();while(rs.next()){Long id=rs.getLong("id");String actno=rs.getString("actno");Double balance=rs.getDouble("balance");Account account=new Account();account.setId(id);account.setActno(actno);account.setBalance(balance);list.add(account);}} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}finally {DBUtil.close(null,ps,null);}return list;}
}

业务层

package com.bank.mvc;import com.bank.exception.AppException;
import com.bank.exception.MoneyNotEnoughException;
import com.bank.utils.DBUtil;import java.sql.Connection;
import java.sql.SQLException;/*** Service:业务* 专门处理Account的业务处理类* 该类只专注业务处理* 主要专注于MVC模式,不需要专注于取什么名字  xxx都可以* @author hrui* @date 2023/9/2 0:49*/
public class AccountService {private AccountDao accountDao=new AccountDao();/*** 完成转账的业务逻辑* @param fromActno* @param toActno* @param money*/public void transfer(String fromActno,String toActno,double money) throws MoneyNotEnoughException, AppException {try(Connection conn= DBUtil.getConnection()){conn.setAutoCommit(false);//查询余额是否充足Account fromAccount = accountDao.selectBtActNo(fromActno);if(fromAccount.getBalance()<money){throw new MoneyNotEnoughException("余额不足");}//程序到这里说明余额够Account toAct=accountDao.selectBtActNo(toActno);//修改余额fromAccount.setBalance(fromAccount.getBalance()-money);toAct.setBalance(toAct.getBalance()+money);//更新数据库int count=accountDao.update(fromAccount);count += accountDao.update(toAct);
//        String str=null;
//        str.toString();//或者//count++;  会向用户提示转账失败  但是转账确已经完成   或者1账户减款而2账户没有加的情况if(count!=2){throw new AppException("转账异常");}conn.commit();} catch (SQLException e) {e.printStackTrace();throw new AppException("转账异常");}}}

相关文章:

MVC模式分层练习

新建库 新建表 插入点数据 先不用MVC模式写功能,来看下缺点是什么 新建一个空项目 选项项目使用的JDK 自己的IDEA总是要重启下 新建模块 因maven还没教 添加框架支持 添加后项目多了这些 添加些必要依赖 这里注意下,如果导入jar包不对可以重新导入下或者是jar包本身出了问…...

ORB-SLAM2算法12之单目初始化Initializer

文章目录 0 引言1 单目初始化Initializer1.1 构造函数1.2 成员函数1.2.1 Initialize1.2.2 FindHomography1.2.3 FindFundamental1.2.4 ReconstructH1.2.5 ReconstructF 2 总结 0 引言 ORB-SLAM2算法7详细了解了System主类和多线程、ORB-SLAM2学习笔记8详细了解了图像特征点提取…...

固定参数-以京东sign逆向为例

前言 在逆向过程中&#xff0c;需要结合frida或unidbg&#xff0c;对整个算法进行一步步的分析&#xff0c;有时候我们分析完某一部分&#xff0c;想要继续往下分析时&#xff0c;需要重新发起请求&#xff0c;这时候的参数往往都已经改变了&#xff0c;这样会打断我们的节奏&a…...

在macOS 上执行sed命令报错问题

错误描述 在macOS 上执行sed命令&#xff0c;报错 sed -i s/book/books/g demo.txt sed: 1: extra characters at the end of d command解决方法 原因是mac的和linux写法不一样 linux sed -i s/book/books/g demo.txtmac sed -i s/book/books/g demo.txt...

ARP欺骗

ARP协议&#xff1a; 地址解析协议&#xff0c;将IP地址转换为对应的mac地址&#xff0c;属链路层协议 ip地址&#xff1a; ip地址本义是为互联网上的每一个网络和每一台主机配置一个唯一的逻辑地址&#xff0c;它的格式表示为&#xff1a;&#xff08;A.B.C.D&#xff09;。其…...

pip切换下载源(多种国内源)

pip切换下载源 一、pip二、使用步骤1.查看源2.切换源 一、pip pip 是一个现代的&#xff0c;通用的 Python 包管理工具 二、使用步骤 1.查看源 使用以下命令查看当前pip的下载源 pip config list2.切换源 在国内使用官方下载依赖往往速度慢&#xff0c;易出错&#xff0c…...

ARM Cortex-M 的 SP

文章目录 1、栈2、栈操作3、Cortex-M中的栈4、MDK中的SP操作流程5、Micro-Lib的SP差别1. 使用 Micro-Lib2. 未使用 Micro-Lib 在嵌入式开发中&#xff0c;堆栈是一个很基础&#xff0c;同时也是非常重要的名词&#xff0c;堆栈可分为堆 (Heap) 和栈 (Stack) 。 栈(Stack): 一种…...

【原创】鲲鹏ARM构架openEuler操作系统安装Oracle 19c

作者:einyboy 【原创】鲲鹏ARM构架openEuler操作系统安装Oracle 19c | 云非云计算机科学、自然科学技术科谱http://www.nclound.com/index.php/2023/09/03/%E3%80%90%E5%8E%9F%E5%88%9B%E3%80%91%E9%B2%B2%E9%B9%8Farm%E6%9E%84%E6%9E%B6openeuler%E6%93%8D%E4%BD%9C%E7%B3%BB%…...

k8s之存储篇---数据卷-挂载

挂载是指将定义在 Pod 中的数据卷关联到容器&#xff0c;同一个 Pod 中的同一个数据卷可以被挂载到该 Pod 中的多个容器上。 数据卷内子路径 有时候我们需要在同一个 Pod 的不同容器间共享数据卷。使用 volumeMounts.subPath 属性&#xff0c;可以使容器在挂载数据卷时指向数…...

无涯教程-JavaScript - TDIST函数

The TDIST function replaces the T.DIST.2T & T.DIST.RT functions in Excel 2010. 描述 该函数返回学生t分布的百分点(概率)​​,其中数值(x)是t的计算值,将为其计算百分点。 t分布用于小样本数据集的假设检验。使用此函数代替t分布的临界值表。 语法 TDIST(x,deg_fr…...

IP子网的划分

文章目录 一、子网掩码1. 产生背景2. 定义3. 分类 二、VLSM算法1. 得出下列参数2. 计算划分结果3. 举例子计算 三、常见子网划分对应关系四、练习IP编址题目需求解题1. 192.168.1.100/282. 172.16.0.58/263. 25.83.149.222/254. 100.100.243.18/205. 10.100.100.100/10 首先可以…...

弹性盒子的使用

一、定义 弹性盒子是一种用于按照布局元素的一维布局方法&#xff0c;它可以简便、完整、响应式地实现各种页面布局。 容器中存在两条轴&#xff0c;主轴和交叉轴(相当于我们坐标轴的x轴和y轴)。我们可以通过flex-direction来决定主轴的方向。 主轴&#xff08;main axis&am…...

软件测试/测试开发丨Selenium 网页frame与多窗口处理

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27048 一、多窗口处理. 1.1、多窗口简介 点击某些链接&#xff0c;会重新打开⼀个窗⼜&#xff0c;对于这种情况&#xff0c;想在新页⾯上操作&#xff0…...

MySQL高阶语句(三)

一、NULL值 在 SQL 语句使用过程中&#xff0c;经常会碰到 NULL 这几个字符。通常使用 NULL 来表示缺失 的值&#xff0c;也就是在表中该字段是没有值的。如果在创建表时&#xff0c;限制某些字段不为空&#xff0c;则可以使用 NOT NULL 关键字&#xff0c;不使用则默认可以为空…...

链表OJ练习(2)

一、分割链表 题目介绍&#xff1a; 思路&#xff1a;创建两个链表&#xff0c;ghead尾插大于x的节点&#xff0c;lhead尾插小于x的节点。先遍历链表。最后将ghead尾插到lhead后面&#xff0c;将大小链表链接。 我们需要在创建两个链表指针&#xff0c;指向两个链表的头节点&…...

ssh常用操作

ssh常用操作 SSH是一种安全协议&#xff0c;ssh是该协议的客户端程序&#xff0c;openssh-server则是该协议的服务端程序 常用系统都自带了ssh客户端程序&#xff0c;服务端程序则可能要安装 密码远程登陆 前提&#xff1a;服务器安装了openssh-server&#xff0c;未安装时…...

从AD迁移至AAD,看体外诊断领军企业如何用网络准入方案提升内网安全基线

摘要&#xff1a; 某医用电子跨国集团中国分支机构在由AD向AzureAD Global迁移时&#xff0c;创新使用宁盾网络准入&#xff0c;串联起上海、北京、无锡等国内多个职场与海外总部,实现平滑、稳定、全程无感知的无密码认证入网体验&#xff0c;并通过合规基线检查&#xff0c;确…...

Flutter系列文章-Flutter在实际业务中的应用

不同场景下的解决方案 1. 跨平台开发&#xff1a; 在移动应用开发中&#xff0c;面对不同的平台&#xff08;iOS和Android&#xff09;&#xff0c;我们通常需要编写两套不同的代码。而Flutter通过一套代码可以构建适用于多个平台的应用&#xff0c;大大提高了开发效率&#x…...

FPGA | Verilog仿真VHDL文件

当VHDL模块中有Generic块时&#xff0c;应该怎么例化&#xff1f; VHDL模块代码 entity GenericExample isgeneric (DATA_WIDTH : positive : 8; -- 泛型参数&#xff1a;数据宽度ENABLE_FEATURE : boolean : true -- 泛型参数&#xff1a;是否启用特定功能);Port ( clk : …...

微服务--Gatway:网关

routes: - id:order_route(路由唯一 标识&#xff0c;路由到order) uri&#xff1a;http://localhost:8020 #需要转发的地址 #断言规则&#xff08;用于路由规则的匹配&#xff09; predicates: -path/order-serv/** -pathlb://order-service # lb: 使用nacos中的本地…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

电脑桌面太单调,用Python写一个桌面小宠物应用。

下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡&#xff0c;可以响应鼠标点击&#xff0c;并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...