拾壹博客拆解改造,页面元素替换(二)

news2024/11/15 9:07:21

页面元素替换

首先要做的当然是换成自己风格的站名和内容啦。

1、网站配置

跟踪前端代码后发现配置是来自后端接口,想着既然入库了,那应该有对应的管理页面吧,果然找到了,就是…演示账号不允许操作!那么接下来要干的事就很明显了,把这个用户搞定!
image.png

2、账号配置

切换到idea发现工作台存在一行报错,根据报错跳转到对应的代码,发现这鉴权方式没见过啊!赶紧面向百度编程。
image.png
Sa-token文档地址:https://sa-token.dev33.cn/
大概了解了下这个框架,简直是懒人福音啊x。然后发现页面上就有用户管理 + 修改密码,那么事情就变得简单了。
image.png

3、文件上传

因为预想中配置的文件服务器是minio,作者只附了本地和七牛两种方式,那么改造开始。

增加minio标签选项

全局搜索图片上传方式,找到对应绑定的字段,加上minio。PS:阿里oss原本也是没有的,但是跟踪后端代码发现字典值2对应的是阿里oss,就先加上了。
image.png

后端代码

跟踪/file/upload接口可以发现,后端是根据fileUploadWay 配置字段决定调用哪个上传策略。

private void getFileUploadWay() {
	strategy = FileUploadModelEnum.getStrategy(systemConfigService.getCustomizeOne().getFileUploadWay());
}

跟踪FileUploadModelEnum发现是个枚举类,那么先加上minio的枚举。
image.png
先在pom.xml引入minio

<!-- Minio -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.2.2</version>
</dependency>

原作者的配置方式是在数据库加入字段,这种方式不太习惯,所以这边minio的配置都加入到配置文件中,后续使用**@Value**注入。

#============================Minio配置信息===================================
minio:
  url: http://ip:9000
  accessKey: minio账号
  secretKey: minio密码
  bucketName: 桶名称
  preurl: http://预览地址

随后仿造aliUploadStrategyImpl创建minio对应的service。

package com.shiyi.strategy.imp;

import com.shiyi.strategy.FileUploadStrategy;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectsArgs;
import io.minio.Result;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.velocity.shaded.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Date;
import java.util.UUID;
import java.util.stream.Collectors;

@Service("minioUploadStrategyImpl")
public class MinioUploadStrategyImpl implements FileUploadStrategy {

    private final Logger logger = LoggerFactory.getLogger(MinioUploadStrategyImpl.class);

    /**
     * 服务地址
     */
    @Value("${minio.url}")
    private String url;

    /**
     * 预览路径前缀
     */
    @Value("${minio.preurl}")
    private String preurl;

    /**
     * 用户名
     */
    @Value("${minio.accessKey}")
    private String accessKey;

    /**
     * 密码
     */
    @Value("${minio.secretKey}")
    private String secretKey;

    /**
     * 存储桶名称
     */
    @Value("${minio.bucketName}")
    private String bucketName;

    private static MinioClient client = null;

    @PostConstruct
    private void init(){
        client = MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
    }

    @Override
    public String fileUpload(MultipartFile file,String suffix) {
        String fileName = null;
        try {
        	String extension = FilenameUtils.getExtension(file.getOriginalFilename());

            fileName = DateFormatUtils.format(new Date(), "yyyy/MM/dd") + "/" + UUID.randomUUID() + "." + extension;
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build();
            client.putObject(args);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return preurl + "/" + bucketName + "/" + fileName;
    }

    /**
     * 删除文件 -- minio
     *
     * @param key   文件url
     * @return      ResponseResult
     */
    @Override
    public Boolean deleteFile(String ...key) {
        if (key.length > 0) {
            //批量删除
            Iterable<DeleteObject> deleteObjects = Arrays.stream(key).map(s -> new DeleteObject(s)).collect(Collectors.toList());

            Iterable<Result<DeleteError>> results = client.removeObjects(
                    RemoveObjectsArgs.builder()
                            .bucket(bucketName)
                            .objects(deleteObjects)
                            .build()
            );

            for (Result<DeleteError> result : results) {
                try {
                    result.get();
                } catch (Exception e) {
                    logger.error(e.getMessage());
                    e.printStackTrace();
                }
            }
        }

        return true;
    }

}

先在入口添加一下注解,再使用swagger调用测试,PS:记得先登录
![image.png](https://img-blog.csdnimg.cn/img_convert/25de1564a7752823ed66d8d1f751c3fb.png#averageHue=#2c2c2b&clientId=u5ccd04dd-8879-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=199&id=u6c178023&margin=[object Object]&name=image.png&originHeight=199&originWidth=2033&originalType=binary&ratio=1&rotation=0&showTitle=false&size=57089&status=done&style=none&taskId=u7ed14748-0b8e-4b09-b099-6807f1e7572&title=&width=2033)
image.png

文件中间表

为啥要用中间表呢,主要是想保护minio的端口。上传和下载都通过代码进行,就不能通过文件层级猜到别的文件路径。以及防止minio突然暴露什么漏洞。【当然如果是项目上用这个才不管呢!】

  1. 建表语句
CREATE TABLE `tb_files` (
  `id` bigint(20) NOT NULL COMMENT '主键id',
  `user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `preview_file` varchar(128) DEFAULT NULL COMMENT '文件minio地址',
  `file_name` varchar(512) DEFAULT NULL COMMENT '原文件名称',
  `content_type` varchar(50) DEFAULT NULL COMMENT '文件类型',
  `is_static` tinyint(1) DEFAULT '0' COMMENT '是否静态资源',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='文件表';
  1. 随便抄一个代码生成器
/**
 * 代码生成器
 */
public class CodeGenerator {

    public static void main(String[] args) {
        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");

        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("dingx");
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖
        /*
         * mp生成service层代码,默认接口名称第一个字母有 I
         * UcenterService
         * */
        gc.setServiceName("%sService"); //去掉Service接口的首字母I
        gc.setIdType(IdType.ASSIGN_ID); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式
        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://ip:port/schema?serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("pwd");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
//        pc.setModuleName(scanner("模块名")); //模块名
        pc.setParent("com.shiyi");
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude(scanner("表名"));
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain =true) setter链式操作
        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
        mpg.setStrategy(strategy);

        // 6、执行
        mpg.execute();
    }

    private static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        System.out.println(("请输入" + tip + ":"));
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }
}
  1. 改造上传代码
private final TbFilesService tbFilesService;

@Override
public String fileUpload(MultipartFile file,String suffix) {
    String fileName;
    TbFiles tbFile = null;
    try {
        String extension = getExtension(file);

        fileName = DateFormatUtils.format(new Date(), "yyyy/MM/dd") + "/" + UUID.randomUUID() + "." + extension;

        //保存上传文件记录
        tbFile = new TbFiles(file.getOriginalFilename(), fileName, file.getContentType());
        if (!tbFilesService.save(tbFile)){
            throw new RuntimeException("插入文件失败");
        }

        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        client.putObject(args);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return preurl + "/" + tbFile.getId();
}
  1. 增加预览接口
public class TbFilesController {

    private final TbFilesService filesService;

    private final MinioUploadStrategyImpl minioUploadStrategy;

    /**
     * 预览
     * @param id
     * @return
     */
    @SaIgnore
    @GetMapping("/preview/{id}")
    @ResponseBody
    public ResponseEntity<StreamingResponseBody> preview(@PathVariable Long id){
        TbFiles file = filesService.getDetail(id);

        //设置头文件Content-type
        HttpHeaders headers = new HttpHeaders();

        // 发送给客户端的数据
        // 设置编码
        if (StringUtils.isNotBlank(file.getContentType())) {
            headers.setContentType(MediaType.valueOf(file.getContentType()));
        }

        //构造返回体
        return ResponseEntity.ok()
                .headers(headers)
                .body(outputStream -> {
                    try (InputStream inputStream = minioUploadStrategy.downloadFile(file.getPreviewFile())){
                        IOUtils.copy(inputStream, outputStream);
                    } catch (Exception e){
                        e.printStackTrace();
                    }
                });
    }
}

这里遇到的坑:
1)使用了ResponseEntity作为返回对象,使用HttpServletResponse的话,Content-type变更了也会被Spring框架自动更改为application/json。查找资料的时候看到很多使用**@GetMappingproduces属性,但是这样就固定了Content-type的内容。
2)不能使用下载的方式获取预览流,
标签中放入地址后虽然接口调用成功了,但是图是裂开的。
3)接口校验忽略接口 @SaIgnore 这个注解是sa-token 1.29版本没有的。这里升级到了
1.32版本。当然也可以改WebMvcConfig文件中的sa-token**拦截器。

  1. 功能测试

上传后查看数据库,已经入库。
image.png
调用preview方法
image.png

  1. 一个警告
!!!
An Executor is required to handle java.util.concurrent.Callable return values.
Please, configure a TaskExecutor in the MVC config under "async support".
The SimpleAsyncTaskExecutor currently in use is not suitable under load.
-------------------------------
Request URI: '/dingx/data/files/preview/1594875366335397890'
!!!

老实说,写了那么久代码第一次遇到warning提示。。
大意就是:默认的SimpleAsyncTaskExecutor已不适用,请自定义一个TaskExecutor。那就加呗,WebMvcConfig加入下列代码。

@Bean
public ThreadPoolTaskExecutor mvcTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(100);
    taskExecutor.setMaxPoolSize(100);
    return taskExecutor;
}

@Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    configurer.setTaskExecutor(mvcTaskExecutor());
}

Nginx强化配置

nginx缓存

proxy_cache_path /root/cache levels=1:2 keys_zone=xd_cache:10m max_size=1g inactive=60m use_temp_path=off;

server {

    location /{
        ... 
        proxy_cache xd_cache;
        proxy_cache_valid 200 304 10m;
        proxy_cache_valid 404 1m; 
        proxy_cache_key $host$uri$is_args$args;
        add_header Nginx-Cache "$upstream_cache_status";
    }
}
配置讲解:
  1. /root/cache:本地路径,用来设置Nginx缓存资源的存放地址
  2. levels=1:2 :默认所有缓存文件都放在上面指定的根路径中,可能影响缓存的性能,推荐指定为 2
  3. 级目录来存储缓存文件;1和2表示用1位和2位16进制来命名目录名称。第一级目录用1位16进制命名,如a;第二级目录用2位16进制命名,如3a。所以此例中一级目录有16个,二级目录有16*16=256个,总目录数为16256=4096个。
  4. 当levels=1:1:1时,表示是三级目录,且每级目录数均为16个
  5. key_zone:在共享内存中定义一块存储区域来存放缓存的 key 和 metadata
  6. max_size :最大 缓存空间, 如果不指定会使用掉所有磁盘空间。当达到 disk 上限后,会删除最少使用的 cache
  7. inactive:某个缓存在inactive指定的时间内如果不访问,将会从缓存中删除
  8. proxy_cache_valid:配置nginx cache中的缓存文件的缓存时间,proxy_cache_valid 200 304 2m 对于状态为200和304的缓存文件的缓存时间是2分钟
  9. use_temp_path:建议为 off,则 nginx 会将缓存文件直接写入指定的 cache 文件中
  10. proxy_cache:启用proxy cache,并指定key_zone,如果proxy_cache off表示关闭掉缓存
  11. add_header Nging-Cache “$upstream_cache_status”:用于前端判断是否是缓存,miss、hit、expired(缓存过期)、updating(更新,使用旧的应答),还原nginx配置,只保留upstream模块
注意:
  1. nginx缓存过期影响的优先级进行排序为:inactvie > 源服务器端Expires/max-age > proxy_cache_valid
  2. 如果出现 Permission denied 修改nginx.conf,将第一行修改为 user root
  3. 默认情况下GET请求及HEAD请求会被缓存,而POST请求不会被缓存,并非全部都要缓存,可以过滤部分路径不用缓存

image.png

vue项目部署至nginx,路由404

查看官网推荐配置,cv一份。
image.png

文章SEO

先在百度搜索资源站配置好自己的网站:http://data.zz.baidu.com/linksubmit/index
找到普通收录,在配置文件中增加配置项

baidu:
  url: http://data.zz.baidu.com/urls?site=blog.dinganwang.top&token=
  sourceurl: https://blog.dinganwang.top/articles/

修改articleSeo方法。作者这边是用for循环实现的批量推送,emmmm老实说有点怪,所以稍微改了下。

@Value("${baidu.url}")
private String baiduUrl;

@Value("${baidu.sourceurl}")
private String sourceUrl;

private final static String SUCCESS = "success";
private final static String REMAIN = "remain";

/**
 *  文章百度推送
 * @return
 */
@Override
public ResponseResult articleSeo(List<Long> ids) {
    String param = "";

    for (Long id : ids) {
        param += sourceUrl + id + "\n";
    }

    HttpEntity<String> entity = new HttpEntity<>(param.trim(), createBdHeader());
    String res = restTemplate.postForObject(baiduUrl, entity, String.class);
    JSONObject JO = JSONObject.parseObject(res);
    if (JO.getInteger(SUCCESS) > 0){
        return ResponseResult.success("成功推送【" + JO.getInteger(SUCCESS) + "】条,剩余量【" + JO.getInteger(REMAIN) + "】条");
    }else {
        return ResponseResult.error("推送失败!");
    }
}

/**
 * 构造百度seo头文件
 * @return
 */
private static HttpHeaders createBdHeader(){
    HttpHeaders headers = new HttpHeaders();
    headers.add("Host", "data.zz.baidu.com");
    headers.add("User-Agent", "curl/7.12.1");
    headers.add("Content-Length", "83");
    headers.add("Content-Type", "text/plain");
    return headers;
}

第二天能够查看头一天的推送情况。
image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/56225.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

stm32f767的fft

仅作自己笔记用 1&#xff0c;FFT函数调用基础知识 采样得到的数字信号&#xff0c;就可以做FFT变换了。N个采样点&#xff0c;经过FFT之后&#xff0c;就可以得到N个点的FFT结果。为了方便进行FFT运算&#xff0c;通常N取2的整数次方。 假设采样频率为Fs&#xff0c;信号频率…

基于Java环境下的高校跳蚤市场商城系统

目 录 摘 要 I Abstract II 1绪论 1 1.1 课题背景 1 1.2 目的和意义 1 1.3 研究现状 2 1.4 研究主要内容 3 2开发平台与技术的介绍 4 2.1 Eclipse简介 4 2.2 Java EE简介 4 2.2.1 Java EE概念 4 2.2.2 Java EE运行模式 4 2.3 Jsp技术简介 5 2.4 Struts 2框架简介 5 2.5 MySQL简…

[附源码]计算机毕业设计springboot新冠疫苗接种预约系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Docker最新超详细教程——Docker创建运行Redis并挂载

Docker最新超详细教程——Docker创建运行Redis并挂载 Docker官网关于Redis的描述 redis - Official Image | Docker Hubhttps://hub.docker.com/_/redis 一、拉取Redis镜像 docker pull <镜像名称>:<版本号> docker pull redis:6.2.27 首先我们要在Docker上获取…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高校教学过程管理系统34085

现在毕设刚开始。时间还有很多&#xff0c;可以从头开始学也可以。毕设其实不难&#xff0c;难的是我们懒散到这种时候再去静下心学。能自己独立完成尽量自己独立完成。相信你看过很多上面回答的&#xff0c;都不建议去某宝。毕竟这一行参差不齐哈。能找到靠谱的也不容易。近期…

Unity Debug的简单封装

对Unity Debug的简单封装 使用前提&#xff1a; Project Settings-Player-Other Settings-Script Define Symbols添加 EnableLog&#xff0c;点击Apply 测试代码&#xff1a; using MTools.Debuger; using UnityEngine;public class NewBehaviourScript : MonoBehaviour {p…

基于PHP+MySQL家庭医生签约预约诊疗管理信息系统

随着时代的发展,人们对医疗方面的要求也越来越高,也是人们更希望通过家庭医生来对自己提供所需的医疗服务,从而享受更加个性化的医疗服务,为此我们开发了本家庭医生签约预约诊疗管理信息系统,通过本系统患者可以享有签约,预约,和诊疗等一系类的服务。 本系统是一个家庭医生签约…

[附源码]Python计算机毕业设计Django基于微信小程序的网络办公系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

qmake 参数

E:\workspace\QtWork\qmake\option.cpp:Option::init() -project 设置qmake生成工程相关文件&#xff0c;如果用qt creator开发的话这个命令参数基本用不到。 -prl 设置qmake生成prl文件。 -set 设置自定义属性&#xff0c;会存放到注册表中。具体参考属性 -unset 取消自定义…

网页JS自动化脚本(六)在特定位置添加元素

在某元素后插入元素 我们这一次在按钮元素后面复制一个一模一样的按钮,所以分为几个步骤,先新建一个一样的元素,然后把相同中的属性赋值给它,再插入到合适的位置,最后再稍微修改一下外观样式即可 首先新建一个input元素,看一下效果 window.onloadfunction(){var theElementdo…

[附源码]Python计算机毕业设计Django基于人脸识别的社区防疫管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Pytest自动化测试框架---(单元测试框架)

unittest是python自带的单元测试框架&#xff0c;它封装好了一些校验返回的结果方法和一些用例执行前的初始化操作&#xff0c;使得单元测试易于开展&#xff0c;因为它的易用性&#xff0c;很多同学也拿它来做功能测试和接口测试&#xff0c;只需简单开发一些功能&#xff08;…

阿里云新用户活动:云服务器ECS 新购、升级报价出炉了!

阿里云新人特惠&#xff0c;阿里云新用户新购升级立享满减&#xff0c;新购升级云服务器ECS &#xff0c;购买热门产品 s6/u1/c6/g6/r6/c7/g7/r7指定配置&#xff0c;可享折上折&#xff01;从未购买过云服务器ECS或者轻量应用服务器的用户一次性可领取3张优惠券。优惠券适用于…

深入浅出Seata的AT模式

单个掉队&#xff0c;导致集体被动摆烂&#xff1b; 一、业务背景 在分布式架构中&#xff0c;事务管理是个无法避开的复杂问题&#xff0c;虽然有多种解决方案&#xff0c;但是需要根据业务去选择合适的&#xff1b; 从个人最近几年的实践经验来看&#xff0c;Seata组件的AT…

【JUC】SpringBoot使用线程池的两种方式 注解和注入

学习笔记一、ThreadPoolTaskExecutor与ThreadPoolExecutor的区别二、编写配置文件ThreadPoolConfig二、编写Controller三、编写Service3.1、注解3.1、注入一、ThreadPoolTaskExecutor与ThreadPoolExecutor的区别 ThreadPoolExecutor 是JDK自1.5添加的线程池。 ThreadPoolTaskE…

排序算法:插入排序,选择排序,冒泡排序

插入排序 一般来说&#xff0c;插入排序都采用in-place在数组上实现。具体算法描述如下&#xff1a; 步骤1: 从第一个元素开始&#xff0c;该元素可以认为已经被排序&#xff1b; 步骤2: 取出下一个元素&#xff0c;在已经排序的元素序列中从后向前扫描&#xff1b; 步骤3: 如…

[附源码]计算机毕业设计-中国传统手工艺销售平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[附源码]计算机毕业设计JAVA校园失物招领平台

[附源码]计算机毕业设计JAVA校园失物招领平台 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

李峋同款会动的爱心Python代码版

最近看到不少关于李峋同款爱心的视频、文章&#xff0c;今天我们也分享一下李峋同款爱心 Python 代码版。要问李峋是谁&#xff1f;我也不太清楚&#xff0c;大家可自行百度&#xff0c;这个是我百度的结果&#xff0c;仅供参考。 简单来说李峋同款爱心就是一个动态的♥型效果&…

【STM32学习(1)】详解STM32时钟体系

一、8051和stm32时钟体系结构区别 HSE&#xff1a;外部高速的振荡时钟&#xff08;8MHZ&#xff09; HSI&#xff1a;内部高速的振荡时钟&#xff08;16MHZ&#xff09; LSI&#xff1a;内部低速的振荡时钟&#xff08;32KHZ&#xff09; LSK&#xff1a;外部低速的振荡时钟&a…