管理系统总结(前端:Vue-cli, 后端Jdbc连接mysql数据库,项目部署tomcat里)

2023-11-01

根据所学的知识, 写一个管理系统, 顺便总结一些知识点

准备:

前端用vue-cli的框架, 后端用jdbc连接数据库, 项目部署tomcat服务器来完成交互

●前端的vue-cli框架搭建可以看 点击跳转 的第二小结
●后端的tomcat在idea里的相关的配置与集成,可以看 点击跳跃

文章目录

一、 前段搭建

在完成点击跳转Vue-cli 项目的搭建之后, 咱去组件官网直接 顺组件 (复制组件), 这里我用的是Element-ui官网的组件,官网点击右边: 点击完成跳转

1. 登录组件

在这里插入图片描述

2. 管理页面

在这里插入图片描述

3.异步请求发送后端, 验证账号

首先使用xios来发送, 因为原生态的ajax代码繁琐
<1>首先要引入axios.js文件或者安装axios的脚手架

$ npm install axios
这里就引入xios.js的组件来使用axios发送请求

<2>下载完成后, 在node_moudules里导入到main.js的全局配置文件里面
在这里插入图片描述

<3>导入后就能直接用axios语法来发送请求
发送get请求

				this.$http.get("http://localhost:8080/webBack_5.14/login?account=jwq&password=111").then(function(resp){
					//业务逻辑代码
				})

发送post请求

				this.$http.post("http://localhost:8080/webBack_5.14/login",this.account).then((resp){
				//业务逻辑代码
				})

4.异步请求发送后端 数据转化json

由于json是一种轻量级的数据格式, 所以前后端传输数据时候, 经常用json格式来传输

在前端可以写一个方法来转化数据格式:

在这里插入图片描述

请求里做参数转json格式,直接发送json的请求
在这里插入图片描述

5.防止通过浏览器地址恶意访问

如果仅仅是通过登录框验证密码还是不够安全, 还可以通过URL地址来直接进行访问, 就会跳过登录的页面

如下:
在这里插入图片描述

直接输入了网站URL的地址, 就直接访问进来了, 根本没有通过账户密码的验证

所以要将一个验证信息放到浏览器里—>(sessionStorage)

sessionStorage

他是浏览器里可以存储数据的容器, 在关闭浏览器时就会清除

因此将用户信息存储到sessionStorage(会话储存) 里 , 在进入具体操作的网页网页时候可以先进行判断, 如果有会话存储里有账号, 那么就可以进行访问, 不然那就回到登录的页面, 这样验证就更加符合需求,

在这里插入图片描述

而且此时的sessionStorage还可以将登录人的信息, 账号放到页面上显示, 就好像京东这些购物软件, 将用户人的登录信息展示到我的这一页面,就可以将操作人的信息放到sessionStorage里面, 随后在哪个页面想要获取渲染在前端时, 就可以随时获取, 非常方便

如下:
在这里插入图片描述
在这里插入图片描述

具体操作

在登录成功后, 将account的数据放入到sessionStorage里面,
在之后每一次请求处理访问登录的请求外的其他请求, 都要验证account

<1>放入account
在这里插入图片描述
在这里插入图片描述
<2>添加web会话跟踪技术
这是在router对象的那个index.js文件里配置
在这里插入图片描述
这样每一次请求的跳转就有了条件, 经过验证, 满足条件才会跳转, 让浏览器的安全性有了基础保障
在这里插入图片描述

提高安全性(session不安全), 使用token来验证

session缺点

  1. 浏览器里的数据时可以随时改的, 就会让一些不法分子走漏洞, 所以在前端验证并不是万全之策
  2. 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存
    中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。
    因此要引入另一种安全的高效的验证操作, token 验证方式

不了解token的可以看这里 点击跳转

具体操作

首先在登录成功之后, 要在后端生成token, 再将token连随响应数据一并发送给前端, 前端得到token之后, 在接下来的每一次发送请求都会将token携带到请求里, 到后端来验证token是否正确, 正确就继续执行操作, 不正确就要返回 token不对的异常信息

生成token:
首先要导入jar包
在这里插入图片描述
由JWT的方式生成token
想了解JWT的可以 点击去看看JWT

JWT的工具类

public class JWTUtil {

    /**
     * jwt 生成 token
     */
    public static String token (Admin admin){
        String token = "";
        try {
             //过期时间 为 1970.1.1 0:0:0 至 过期时间 当前的毫秒值 + 有效时间
            Date expireDate = new Date(new Date().getTime() +3600*1000);
             //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
           //设置头部信息
            Map<String,Object> header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带 id,账号信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("id",admin.getId())
                    .withClaim("account",admin.getAccount())
                    .withExpiresAt(expireDate)
                    .sign(algorithm);
        }catch (Exception e){
            e.printStackTrace(); return null;
        }
        return token;
    }

    /**
     * 验证 token 的方法
     * @param token
     * @return
     */
    public static boolean verify(String token){
        try {
         //验签
            Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {//当传过来的 token 如果有问题,抛出异常
            return false;
        }
    }

    /**
     * 获得 token 中 playload 部分数据,按需使用
     * @param token
     * @return
     */
    public static DecodedJWT getTokenInfo(String token){
        return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);
    }
}

将token信息封装到admin对象里, 一并返回前端
在这里插入图片描述
前端将信息放入浏览器的会话存储里
在这里插入图片描述
请求发送时,后端验证token

先想想, 后端在接到前端请求时, 要验证token,可以写在一个过滤器里面, 除了登录请求外都要走这个过滤器, 那么问题来了, 如何使得这个过滤器除了登录请求外都走这个过滤器呢?
<1>过滤器的配置

我们可以通过给走这个过滤器的请求添加一层级的路径, 具体如下图
在这里插入图片描述
在这里插入图片描述

这样就可以区分经过验证token过滤器与不验证token过滤器的请求了, 不验证就直接写请求地址, 验证就加上一层级的/token

6.添加请求拦截器

由于我们的每一次请求都要将token信息发送给后端, 索性就放在响请求对象里的请求头的区域
那我们是不是每次请求都要设置请求头啊, 麻烦不麻烦
后端有没有将每次请求拦截下来的东西, 再设置请求头的内容, 你还别说还真有, 响应拦截器
这是

这是在每次请求时,将token放在请求的请求头区域里, 到后端浏览器调用
在这里插入图片描述

7. 响应拦截器

在前端处理后端响应回来的状态码时, 每一个组件对相同部分状态码总是同一个业务流程, 如: 500 状态码时候, 就会弹出服务器异常的信息, 那这样会繁琐很多, 使得代码冗余

在每次接收响应时, 可以根据状态码来做统一给用户做出响应结果, 可以将那些状态码放入响应拦截器里

在这里插入图片描述

8.Main组件添加子组件,来展示学生

  1. 首先定义组件

在Main组件点击学生管理, 就会到达studentList组件
在这里插入图片描述

List组件的生命周期函数mounted(页面加载完成调用), 写一个接收后端响应数据到Vue对象里的studentList的方法
在这里插入图片描述

  1. 注册组件

在router对象性里注册组件, 由于此时的组件是在Main组件里展示, 所以就要在Main组件下定义子组件

在这里插入图片描述

  1. 在Main组件(父组件)添加来展示不同组件

在这里插入图片描述

时间转化问题

由于后端从数据库从数据库接收到学生的注册信息, 会默认将数据库的Data类型转化long类型, 在渲染到前端, 就会是时间戳的格式, 如下图:
数据库里时间:
在这里插入图片描述
渲染到前端:
在这里插入图片描述

所以要格式化student类里oper_time(学生注册时间)的属性, 可以添加注解@JsonFornmat(),
这样在转json时候就会格式化, 响应到前端就会是 年月日 时分秒的格式
在这里插入图片描述

9.引入添加学生的功能

首先,在element-ui里引入功能的组件样式, 然后给组件添加事件, 事件就是打开一个类似于登录的表单, 点击保存之后, 向后端发送一个请求, 通过调取控制层,业务层,数据层将数据保存到数据库里

保存学生的表单,在选择专业时候, 专业不能是固定的, 不然以后更改专业还得改代码, 代码灵活度太低, 所以专业数据就要从数据库获取

点击调取openAddDiolog()方法, 将新增学生的弹窗设置可见(就展示出来)
在这里插入图片描述

导入组件

因为一个组件里写太多东西, 不方便改动, 那么就可以通过导入组件的方式将新增学生的内容写在另一个.vue组件里, 之后通过导入就可以了
Add组件:
在这里插入图片描述
dialogFormVisible:这是对话框的属性, 表示的是一个值, 这个值如果是true表示对话框可见, 如果false那就表示对话框是不可见, 可以通过调用之前的openAddDiolog()的方法来给他赋值

在List组件里定义Add组件在这里插入图片描述

点击新增就会调用openAddDiolog方法, 将新增学生弹窗改成可见在这里插入图片描述

解决增加学生表单里的专业问题

在弹窗里的内容加载完成之后, 就调用生命周期函数, 将数据库里的专业信息展示到表单里
在这里插入图片描述

在这里插入图片描述

二、后端搭建

后端使用的是idea写代码工具, 集成了tomcat服务器

1. 项目构建

后端结构: 如下
在这里插入图片描述

2. 封装连接数据库的代码

由于要有许多的增删改查, 与数据库相关的操作, 所以就封装一下, 以后跟方便用
<1>首先先在src目录下新建一个. properties的文件
在这里插入图片描述
<2>新建一个工具类
工具类将加载驱动, 获取Connection连接对象, 释放资源一些操作封装成静态方法, 用的时候直接拿

就叫做JdbcUtil的类

public class JdbcUtil {

    private static String dirver = null;
    private static String url = null;
    private static String username = null;
    private  static String password = null;

    //获取数据库的外部文件
    //这里放在静态代码块里, 在第一次new对象时候, 就需要加载驱动
    static {
        try {
        //通过字节输入流来读取对应的properties文件
        InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
        //再将读取到的文件放入到jdk里的properties对象里
        Properties pop = new Properties();
        //来获取外部的db.properties数据
        pop.load(in);

        //对应属性赋对象方法
        dirver = pop.getProperty("driver");
        url = pop.getProperty("url");
        username = pop.getProperty("username");
        password = pop.getProperty("password");

        //加载驱动
            Class.forName(dirver);
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("java获取Connection对象错误");
            e.printStackTrace();
        }
    }
    //获取连接对象
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }
    //释放连接对象的资源
    public void relese(Connection con, Statement sta, ResultSet res){
        if (res!=null){
            try {
                res.close();
            } catch (SQLException throwables) {
                System.out.println("sql接收数据集合ResultSet关闭异常");
                throwables.printStackTrace();
            }
        }
        if (sta!=null){
            try {
                sta.close();
            } catch (SQLException throwables) {
                System.out.println("sql接收数据集合ResultSet关闭异常");

                throwables.printStackTrace();
            }
        }
        if (con!=null){
            try {
                res.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

3. 登录判断账号

<1>与数据库交互的Dao层代码展示


LoginDao

public class LoginDao {
    public Admin checkAccount(String account,String passWord) throws SQLException {
        Connection connection = null;
        PreparedStatement ps =null;
        ResultSet resultSet = null;
        Admin admin = null;
        JdbcUtil jdbcUtil = new JdbcUtil();

		//直接通过类调取方法来获取连接对象
        connection = jdbcUtil.getConnection();
    	//  ps = connection.prepareStatement("select account password from admin where account="+"\'"+account+"\'");
        ps = connection.prepareStatement("select id, account from admin where account=? and password=?");
        ps.setObject(1, account);
        ps.setObject(2, passWord);
        resultSet = ps.executeQuery();

        //如果有结果, 说明有该账号
        while(resultSet.next()){
            admin = new Admin();
            admin.setId(resultSet.getInt("id"));
            admin.setAccount(resultSet.getString("account"));
            break;
        }
        //释放连接数据库资源
        jdbcUtil.relese(connection,ps,resultSet);

        return admin;
    }
}

在这里插入图片描述

这三个地方需要注意一下
<1>第一部分 在判断登录这个Dao里, 此方法不能仅仅判断账号密码是否正确, 还要获取返回的那个admin对象

在实际项目中, 难道后天不需要账户信息吗?
就拿淘宝例子来说把, 是不是当你买个东西之后,再次登录时候就给你推类似的一些东西, 这里就是后天已经记录了你买的东西, 所以登录时候就知道给你推相似的商品了

<2>不能直接将用户的账号注入到SQL里查找

 ps = connection.prepareStatement("select account password from admin where account="+"\'"+account+"\'");

这一行代码, 可能会让一些 偷奸耍滑 的人钻空子, 你想想, 直接获取到的账号信息放入sql语句查找,

如果有一个用户输入account: 1==1, 那你此处sql的where条件不就形同虚设了嘛, 随便进入管理系统, 那你就等着被炒鱿鱼把

所以要用格式占位控制符来代替

        ps = connection.prepareStatement("select id, account from admin where account=? and password=?");
        ps.setObject(1, account);
        ps.setObject(2, passWord);

这不就肥肠完美么


<2>业务处理层LoginService

public class LoginServlet extends HttpServlet {

    @Override
    public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
        String account = req.getParameter("account");
        String password = req.getParameter("password");
        CommonRes commonRes = null;
        try{
            LoginDao loginDao = new LoginDao();
            Admin admin = loginDao.checkAccount(account, password);
            System.out.println(admin);
            if (admin!=null){
                //生成token
                String token = JWTUtil.token(admin);
                admin.setToken(token);
                commonRes = new CommonRes(200,admin,"登录成功");
            }else{
                commonRes = new CommonRes(201,"账号或密码错误");
            }
        }catch(Exception e){
            e.printStackTrace();
            commonRes = new CommonRes(500,"服务器异常");
        }
        //将common结果转化成jason格式返回
        resp.setContentType("text/html;charset=UTF-8");
        Writer writer = resp.getWriter();
        ObjectMapper mapper = new ObjectMapper();
        String jsonstr = mapper.writeValueAsString(commonRes);
        writer.write(jsonstr);
    }

代码解读
在这里插入图片描述
由于前端用的是axios的请求发送框架, 所以数据格式在经过服务器内部的一系列处理之后, 就会变成json的键值对格式,
所以后端可以直接 用 req.getParameter(“account”);获取对应参数值

        String account = req.getParameter("account");
        String password = req.getParameter("password");

3. 解决前后端编码不一致的问题问题

在前端向后端发送带参数的请求, 后端获取时, 浏览器默认发送的是ISO8859-1格式的编码 , 而这种编码格式是不能解析中文的, 所以就有乱码的出现
也就是你在request,getParameter(“参数名”)时候, 会是乱码

所以在获取参数之前,要对请求 设置编码
request.setContetnType("text/html;charset=utf-8");, 在请求头设置编码
同理, 后端服务器给前端做出响应的时候也应该设置响应编码, 否则会出现前端接收响应时, 响应的是乱码问题
response.setContetnType("text/html;charset=utf-8")

由于每次接收请求与响应数据都要设置编码格式, 所以就可以将上面两行代码放到过滤器里面

5. 解决跨域问题

跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。但是一般情况下不能这么做,它是由浏览器的同源策略造成

所以可以告诉浏览器可以访问, 可以在响应头里设置

我从后端来解决这个问题

由此我们可以写过一个过滤器来实现

public class CorsFilter implements Filter {
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        //允许携带Cookie时不能设置为* 否则前端报错
        httpResponse.setHeader("Access-Control-Allow-Origin", httpRequest.getHeader("origin"));//允许所有请求跨域
        httpResponse.setHeader("Access-Control-Allow-Methods", "*");//允许跨域的请求方法GET, POST, HEAD 等
        httpResponse.setHeader("Access-Control-Allow-Headers", "*");//允许跨域的请求头
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");//是否携带cookie

        filterChain.doFilter(servletRequest, servletResponse);
    }
}

并且在web.xml里配置哪些业务经过 过滤器

    <filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.jwq.webback.filter.CorsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>corsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

6. 后端对返回结果进行封装

由于每次对后端结果进行返回时候,只能一个一个返回, 所以此时可以封装一个返回的结果集

commonRes

public class CommonRes {
    private int code;
    private Object data;
    private String message;

    public CommonRes(int code, Object data, String message) {
        this.code = code;
        this.data = data;
        this.message = message;
    }

    public CommonRes(int code, String message) {
        this.code = code;
        this.message = message;
    }

    //在转化json格式要通过反射机制用set, get方法来取值
    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

代码解析
在这里插入图片描述
注意: 这里必须是有set,get方法, 因为在后面的json返回格式, 必须要通过反射机制转化json格式

7. 后端对返回结果进行转化json格式后进行响应

<1>首先要导入jar包
在这里插入图片描述
<2>在使用mapper对象里的writeValuesAsString()对响应结果进行json格式的处理

        Writer writer = resp.getWriter();
        ObjectMapper mapper = new ObjectMapper();
        //commonRes这是上面说的返回结果集对象,放入mapper对象的
        //方法里,转json格式
        String jsonstr = mapper.writeValueAsString(commonRes);
        writer.write(jsonstr);

<3>json响应结果查看

在这里插入图片描述
注意: 这里的message响应的是中文, 所以要设置响应头编码

可以设置一个过滤器, 将请求编码与响应编码一起设置了

public class EncodFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        response.setContentType("text/html;charset=UTF-8");
        //让进入到过滤器里的请求, 离开当前的过滤器, 继续向后执行, 后一个可能是过滤器,也可以是servlet
        filterChain.doFilter(servletRequest,servletResponse);
    }
}


8. List组件展示学生操作的处理代码(Contral层, service层, dao层)

由于学生相关的操作用的是一个service处理层, 在相同的get或者post请求下, 后端就要区分不同请求了,

可以在前端发送请求时候给一个标记, mark
在这里插入图片描述

后端获取参数进行, 进行判断
在这里插入图片描述


展示学生的service业务层(暂时Contral与service层不分离)

    /**
     * 展示学生的方法
     * @return
     * @throws SQLException
     */
    public List outStudent() throws SQLException {
        StudentDao studentDao = new StudentDao();
        List<Student> students = studentDao.outStudent();
        return students;
    }

dao层

   /**
     * 查询所有学生的方法
     * @return
     * @throws SQLException
     */
    public List<Student> outStudent() throws SQLException {
        List<Student> majors= new ArrayList<>();
        JdbcUtil jdbcUtil = new JdbcUtil();
        Connection connection = jdbcUtil.getConnection();
        PreparedStatement ps = connection.prepareStatement("SELECT\n" +
                "s.`num`,\n" +
                "s.name,\n" +
                "s.gender,\n" +
                "s.address,\n" +
                "s.phone,\n" +
                "m.name mname,\n" +
                "a.account aname,\n" +
                "s.oper_time FROM student s\n" +
                "LEFT JOIN major m\n" +
                "  ON s.majorid = m.id\n" +
                "LEFT JOIN admin a\n" +
                "  ON s.adminid = a.id");
        ResultSet resultSet = ps.executeQuery();

        while(resultSet.next()){
            Student major = new Student();
            major.setNum(resultSet.getInt("num"));
            major.setName(resultSet.getString("name"));
            major.setGender(resultSet.getString("gender"));
            major.setAddress(resultSet.getString("address"));
            major.setPhone(resultSet.getString("phone"));
            major.setMname(resultSet.getString("mname"));
            major.setAname(resultSet.getString("aname"));
            major.setOperTime(resultSet.getTimestamp("oper_time"));//年月日时分秒
            majors.add(major);
        }
        //释放资源
        jdbcUtil.relese(connection,ps,resultSet);
        return majors;
    }

9. 新增学生操作的处理代码(Contral层, service层, dao层)

10. 发送数据库的专业的代码

响应专业的业务层

    /**
     * 展示专业的方法
     * @return
     * @throws SQLException
     */
    public List outMajor() throws SQLException {
        StudentDao studentDao = new StudentDao();
        List<Major> majors = studentDao.outMajor();
        System.out.println(majors);
        return majors;
    }

dao层

    /**
     * 返回学生专业的方法
     * @return
     * @throws SQLException
     */
    public List<Major> outMajor() throws SQLException {
        List<Major> majors= new ArrayList<>();
        JdbcUtil jdbcUtil = new JdbcUtil();
        Connection connection = jdbcUtil.getConnection();
        PreparedStatement ps = connection.prepareStatement("select id, name from major");
        ResultSet resultSet = ps.executeQuery();

        while(resultSet.next()){
            Major major = new Major();
            major.setNum(resultSet.getString("id"));
            major.setName(resultSet.getString("name"));
            majors.add(major);
        }

        //释放资源
        jdbcUtil.relese(connection,ps,resultSet);
        return majors;
    }

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

管理系统总结(前端:Vue-cli, 后端Jdbc连接mysql数据库,项目部署tomcat里) 的相关文章

随机推荐

  • C语言实现移位密码体制

    问题描述 输入密钥K的值 加密算法 e x x k mod 26 即当前明文字母顺序 如A为1 加上K值之后对应的字母即为密文 解密算法 d y y k mod 26 与加密相反 解密是当前密文字母顺序减去K值对应的字母即为明文 26即26
  • python变量,数据类型,运算符

    这里写自定义目录标题 1 变量 python的变量不需要声明 变量在被使用前必须赋值 变量被赋值后才会被创建 变量赋值和其他语言一样 通过 赋值 例如 usr bin python3 a 1 整型变量 b 1 0 浮点型变量 cc my 字
  • R语言:常用apply函数(apply,tapply,sapply,lapply)用法介绍

    apply函数 对矩阵 数据框 数组 二维 多维 等矩阵型数据 按行或列应用函数FUN进行循环计算 并以返回计算结果 apply X MARGIN FUN X 数组 矩阵 数据框等矩阵型数据 MARGIN 按行计算或按按列计算 1表示按行
  • VsCode 下如何安装shader glsl开发环境

    1 2 安装后搜索glsl canvas 3 glsl linter 能判断语法是否错误的扩展插件 之后去https github com KhronosGroup glslang releases下载glslang 4 文件 首选项 用户
  • [LeetCode] Invert Binary Tree - 二叉树翻转系列问题

    目录 1 Invert Binary Tree 二叉树翻转 递归 题目概述 Invert a binary tree 4 2 7 1 3 6 9 to 4 7 2 9 6 3 1 Trivia This problem was inspir
  • Android依赖剔除和冲突解决

    剔除依赖 模块下build gradle 1 通过包名 模块名剔除 configurations all all exclude group com google guava module guava 2 通过包名剔除 configurat
  • 中小型企业网络组网与配置

    某企业拥有多个部门 如财务部 研发部 技术部等 每个部门使用的 IP 地址网段各不相同 为了便于管理 现需要将同一种部门的业务划分到同一 VLAN 中 不同类型的部门划分到不同 VLAN 中 二层交换原理 二层交换是指数据帧在数据流链路层的
  • C++中stack用法

    c stl栈容器stack用法介绍 stack堆栈容器 堆栈是一个线性表 插入和删除只在表的一端进行 这一端称为栈顶 Stack Top 另一端则为栈底 Stack Bottom 堆栈的元素插入称为入栈 元素的删除称为出栈 由于元素的入栈和
  • (科普)nlp-图解Attention+Transformer

    看文之前 容我多说句 写出来这篇文的作者们 牛逼轰轰 看不懂的好像懂了点什么 看得懂的好像又懂了什么 十万万个点赞 图解Attention seq2seq模型 NLP常用于生成任务的seq2seq结构 如 机器翻译 文本摘要 图像描述生成
  • java学习从入门到进阶的四个阶段送给迷茫的你

    写这篇总结 主要是记录下自己的学习经历 算是自己对知识的一个回顾 也给想要学习 Java 的提供一些参考 对于一些想要学习Java 又不知道从哪里下手 以及现在有哪些主流的 Java 技术 想必大家学习一门技术 前期都很想看到一些结果或成就
  • docker搭建rocketmq集群

    借鉴于 https www cnblogs com qdhxhz p 11096682 html 但是其中有一些错误 本人进行了修改 docker compose yml version 3 5 services rmqnamesrv a
  • RTX3060下双系统安装Ubuntu22.04并配置显卡驱动(超简单)、安装cuda12.1

    首先准备一个启动盘 准备具体步骤在此省略 在windows下准备一块未分区的磁盘空间 插入U盘重启电脑 在重启过程中一直按DEL键 不同电脑按键不同 进入BIOS界面 直接选择U盘空间 点击continue等待 其他的不用管 只需要点两下
  • JDK编译时出现乱码问题(以JDK8(1.8)和JDK17为例)

    先看代码 写个最简单的HelloWorld public class HelloWorld public static void main String args System out println Hello World System
  • 42个Python实用小例子[内附200+代码地址]

    经常有同学苦恼 学了python基础之后找不到合适的练手机会 为此 有位热心人创建了一个项目 搜集整理了一堆实用的python代码小例子 这些小例子包括但不限于 Python基础 Web开发 数据科学 机器学习等方向 短小精炼 力争让你60
  • 深度优先遍历DFS (岛屿问题)java

    算法之深度优先遍历 DFS 最近在学习DFS和BFS 所以做一些学习的笔记 这里是深度遍历 首先 比较常见的深度遍历题目就是网格题 可抽象为二维数组 在LeetCode中常见的是岛屿问题 思想 深度优先遍历的思想可以理解为 找到一个起始点S
  • Vue基础--Vue中的双向绑定v-model指令

    一 v model的作用和使用场景 1 1 v model指令介绍 期望的绑定值类型 根据表单输入元素或组件输出的值而变化 可以下下面元素使用
  • BSM的两个基本问题与python实现(欧式期权定价公式)

    在我们的定义中 定量分析是数学或统计学方法在市场数据上的应用 John Forman BSM定价模型的两个基本问题 隐含波动率 以某些到期日的期权报价倒推出这些期权的隐含波动率 并汇出图表 这是期权交易者和风险管理者每天都要面对的任务 蒙特
  • c++ 引用 函数重载

    定义一个学生的结构体 包含学生的姓名 年龄 成绩 性别 学生的成绩 姓名 定义为私有权限 定义一个学生类型的结构体变量 设置公有函数用于给学生的成绩和名字进行赋值 结构体中的函数 结构体中声明 结构体外定义 include
  • 8个常用JavaScript对象方法

    1 Object assign 作用 将所有可枚举的自身属性从一个或多个源对象复制到目标对象 语法 Object assign target sources 参数 target 目标对象 应用源属性的对象 修改后返回 sources 源对象
  • 管理系统总结(前端:Vue-cli, 后端Jdbc连接mysql数据库,项目部署tomcat里)

    根据所学的知识 写一个管理系统 顺便总结一些知识点 准备 前端用vue cli的框架 后端用jdbc连接数据库 项目部署tomcat服务器来完成交互 前端的vue cli框架搭建可以看 点击跳转 的第二小结 后端的tomcat在idea里的