《SpringBoot+Vue》Chapter04 SpringBoot整合Web开发

news2024/12/22 21:24:32

返回JSON数据

默认实现

依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

在springboot web依赖中加入了jackson-databind作为JSON处理器

创建一个实体类对象

public class Book {
    private String name;
    private String author;
    @JsonIgnore
    private Float price;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date publicationDate;
}

创建BookController

@Controller
public class BookController {
    @GetMapping("/book")
    @ResponseBody
    public Book book() {
        Book book = new Book("bookName", "bookAuthor", 100f, new Date());
        return book;
    }
}

自定义Json转换器

Gson

Gson是google的一个开源JSON解析框架。使用Gson,需要加入Gson依赖,并去除默认的jackson-databind

 <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
</dependency>

SpringBoot中默认提供了Gson自动转换,因此Gson的依赖添加后,就可以直接使用Gson。但是在Gson进行转换时,如果想对日期数据进行格式化。需要开发者自定义HttpMessageConverter自定义HttpMessageConverter

 @Bean
    GsonHttpMessageConverter gsonHttpMessageConverter() {
        GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
        GsonBuilder gsonBuilder = new GsonBuilder();
        //设置时间格式
        gsonBuilder.setDateFormat("yyyy-MM-dd");
        //设置gson解析时遇到protected修饰的字段被过滤掉
        gsonBuilder.excludeFieldsWithModifiers(Modifier.PROTECTED);
        Gson gson = gsonBuilder.create();
        converter.setGson(gson);
        return converter;
    }
fastjson

fastjson是阿里巴巴的一个开源JSON解析框架。是目前最快的JSON解析框架

静态资源访问

默认策略

SpringBoot中对于SpringMVC的自动化配置都在WebMvcAutoConfiguration类
SpringBoot默认会过滤所有的静态资源、而静态资源的位置一共有5个:

  • classpath:/META-INF/resources
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/
  • /


    资源文件优先级

自定义策略

在配置文件中定义
spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=classpath:/static/
  • 过滤规则为/static/** 静态资源位置为classpath:/static/
Java编码定义
public class MyWebMvcConfig implements WebMvcConfigurer{
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry){
  registry.addResourceHandler("/static/**")
              .addResourceLocations("classpath:/static/")
}
}

文件上传

单文件上传

首先创建一个SpringBoot项目并添加spring-boot-starter-web依赖
在resources目录下的static目录创建一个upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="uploadFile" value="选择文件">
    <input type="submit" value="上传">
</form>
</body>
</html>

创建文件上传接口

 @PostMapping("/upload")
    public String upload(MultipartFile uploadFile, HttpServletRequest req) {
        String realPath = req.getSession().getServletContext().getRealPath("/uploadFile");
        String format = sdf.format(new Date());
        File folder = new File(realPath + format);
        if (!folder.isDirectory()) {
            folder.mkdirs();
        }
        String oldName = uploadFile.getOriginalFilename();
        String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."), oldName.length());
        try {
            uploadFile.transferTo(new File(folder, newName));
            String filePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/uploadFile/" + format + newName;
            return filePath;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "上传失败";
    }

@ControllerAdvice

全局异常处理

@ControllerAdvice最常见的使用场景就是全局异常处理

@ControllerAdvice
public class CustomExceptionHandler {
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public void uploadException(MaxUploadSizeExceededException maxUploadSizeExceededException,
                                HttpServletResponse resp){
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = null;
        try {
            writer = resp.getWriter();
            writer.write("超出文件大小限制");
            writer.flush();
            writer.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

当系统启动时,标记@ControllerAdvice就会被扫描到Spring容器中,然后在方法上添加@ExceptionHandler注解,其中定义的MaxUploadSizeExceededException.class表明该方法用来处理MaxUploadSizeExceededExceptioon类型的异常。

添加全局数据

@ControllerAdvice是一个全局数据处理组件。可以在@ControllerAdvice中使用@ModelAttribute注解配置全局数据

@ControllerAdvice
public class GlobalConfig {
    @ModelAttribute(value = "info")
    public Map<String,String> userInfo() {
        HashMap<String, String> map = new HashMap<>();
        map.put("username", "lgz");
        map.put("gender", "男");
        return map;
    }
}
  • 在全局配置中添加userInfo方法,返回map,该方法有一个注解@ModelAttribute,其中的value属性表示这条返回数据的key,而方法的返回值是返回数据的value
  • 在任意请求的Controller中,通过Model参数可以获取map数据

请求参数预处理

@ControllerAdvice结合@InitBinder能实现请求参数预处理,即将表单中的数据绑定到实体类上时进行一些额外处理
例如有两个实体类Book和Author

public class Book {
    private String name;
    private String author;
//.....getter/setter
}
public class Author {
    private String name;
    private int age;
//......getter/setter
}

Controller

@RestController
public class InitBinderController {
    @GetMapping("/book")
    public String book(Book book, Author author) {
        return book.toString() + ">>>" + author.toString();
    }
}

这样在传递参数时,两个实体类中的name就会容易混淆。@ControllerAdvice结合@InitBinder可以顺利解决该问题

@RestController
public class InitBinderController {
    @GetMapping("/book")
    public String book(@ModelAttribute("a") Book book,
                       @ModelAttribute("b") Author author) {
        return book.toString() + ">>>" + author.toString();
    }
}

配置@ControllerAdvice

  @InitBinder("a")
    public void init(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("b.");
    }

    @InitBinder("b")
    public void init2(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("a.");
    }
  • @InitBinder("b")表示该方法是处理@ModelAttribute("b")对应的参数的,第二个@InitBinder("a")表示该方法是处理@ModelAttribute("a")对应的参数的

然后在浏览器中访问:http://localhost:8080/book?b.name=bname&b.author=bauthor&a.name=aname&a.age=aAge即可成功地区分出name属性

  • WebDataBinder对象中,还可以设置允许的字段、禁止的字段、必填字段以及验证器等

自定义错误页

@ControllerAdvice可以处理应用级别的异常,有一些容器级别的错误就处理不了。
在SpringBoot中,默认情况下,404、500等会有统一的处理页面。
SpringBoot在返回错误信息时不一定返回HTML页面,而是根据实际情况返回HTML页面或者一段JSON
SpringBoot中的错误默认是由BasicErrorContoller类来处理的

@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map<String, Object> model = Collections
            .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
    }

    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new ResponseEntity<>(status);
        }
        Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
        return new ResponseEntity<>(body, status);
    }

errorHtml方法用来返回错误HTML页面,error用来返回错误JSON
DefaultErrorViewResolver是SpringBoot中默认的错误信息视图解析器,SpringBooot默认是在error目录下查找4xx、5xx的文件作为错误视图,找不到时会回到errorHtml中,然后使用error作为默认的错误页面视图名,如果error的视图也找不到,用户就会看到默认的错误提示页面

简单配置

如果想自定义错误页面,只需要提供4xx、5xx的页面即可。
如果不需要向用户展示详细的错误信息,可以把错误信息定义成静态页面,直接在resources/static目录下创建error目录,然后在error目录中创建错误展示页面,错误展示页面的命名规则有:

  • 4xx.html、5xx.html
  • 404.html、405.html、500.html
    此时当用户访问一个不存在的网站时,就会展示404.html中的内容
  • 动态页面
    如果采用视图模板技术,先添加依赖,然后在templates目录下创建error目录,然后创建错误展示页


    error目录

CORS支持

CORS:是一种跨域资源共享技术标准,目的就是为了解决前端的跨域请求。CORS支持多种HTTP请求
定义一个Controller

@RestController
@RequestMapping("/book")
public class BookController {
    @PostMapping("/")
    public String addBook(String bookName) {
        return "receive" + bookName;
    }

    @DeleteMapping("{id}")
    public String delBook(@PathVariable("id") Long id) {
        return String.valueOf("id");
    }
}

配置跨域

跨域有两个配置地方,

  • 一个是直接在相应的请求方法上加注解
@RestController
@RequestMapping("/book")
public class BookController {
    @PostMapping("/")
    @CrossOrigin(value = "http://localhost:8081",maxAge = 1800,allowedHeaders = "*")
    public String addBook(String bookName) {
        return "receive" + bookName;
    }

    @DeleteMapping("{id}")
    @CrossOrigin(value = "http://localhost:8081",maxAge = 1800,allowedHeaders = "*")
    public String delBook(@PathVariable("id") Long id) {
        return String.valueOf("id");
    }
}
  • @CrossOrigin中的value表示支持的域,这段代码中表示来自http://localhost:8081域的请求是支持跨域
  • maxAge表示探测请求的有效期 单位是秒
  • allowedHeaders表示允许的请求头,*表示所有请求头都被允许

使用全局配置 创建配置类Config

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/book/**")
                .allowedHeaders("*")
                .allowedMethods("*")
                .maxAge(1800)
                .allowedOrigins("http://localhost:8081");
    }
}

配置类与XML配置

SpringBoot的配置类需要添加@Configuration注解,@ComponentScan注解会扫描所有的Spring组件。也包括@Configuration

注册拦截器

创建拦截器实现HanlderInterceptor接口

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandler>>>>");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandler>>>>");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion>>>>");
    }
}

拦截器中的方法将按照

preHandle->Controller->postHandle->afterCompletion
  • 只有preHandle方法返回true时后面的方法才会执行,
  • 当拦截器内存在多个拦截器时postHandler在拦截器内的所有拦截器返回成功时才会调用
  • afterCompletion只有preHandler返回true才调用
  • 若拦截器内的第一个拦截器的preHandle返回false,则后面的方法都不执行
    配置拦截器
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/book/**")
                .allowedHeaders("*")
                .allowedMethods("*")
                .maxAge(1800)
                .allowedOrigins("http://localhost:8081");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/hello");
    }
}

启动系统任务

有一些特殊的任务需要在系统启动时执行,配置文件加载,数据库初始化等操作。SpringBoot对此提供了两种解决方案 CommandLineRunner 和 ApplicationRunner

CommandLineRunner

SpringBoot项目在启动时会遍历所有CommandLineRunner的实现类并调用其中的run方法,如果有多个实现类,那么可以使用@Order注解对这些实现类的调用顺序进行排序

@Component
@Order(1)
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("first runner"+ Arrays.toString(args));
    }
}
@Component
@Order(2)
public class MyCommandLineRunner2 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("second runner"+ Arrays.toString(args));
    }
}

  • @Order(1)注解用来描述CommandLineRunner的执行顺序,数字越小越先执行
  • run方法中是调用的核心逻辑,参数是系统启动时传入的参数

ApplicationRunner

ApplicationRunner和CommandLineRunner基本一致,区别主要体现在run方法的参数上

整合Servlet、Filter和Listener

  • @WebServlet标记HttpServlet
  • @WebListener标记Listener
  • @WebFilter标记Filter
  • 在项目入口类上添加@ServletComponentScan注解,实现对Servlet、Filter以及Listener的扫描

路径映射

在使用页面模板后,用户需要通过Controller才能访问页面,一些页面需要在控制器中加载数据,然后渲染,才能显示出来。还有一些页面在控制器中不需要加载数据,只是完成简单的跳转。对于这种页面,可以直接配置路径映射,提高访问速度

 @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/index").setViewName("index");
    }

配置AOP

AOP中的概念

AOP中的概念

SpringBoot支持

SpringBoot在Spring的基础上对AOP的配置提供了自动化配置解决方案:spring-boot-starter-aop,使开发者能够更加便捷地在SpringBoot项目中使用AOP

  • 添加AOP依赖
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
  • 创建一个测试的业务Service类
@Service
public class UserService {
    public String getUserById(Integer id) {

        System.out.println("getUserById = " + id);
        return "user";
    }
    public void deleteUserById(Integer id) {
        System.out.println("deleteUserById"+ id);
    }
}
  • 创建切面
@Component
@Aspect
public class LogAspect {

    @Pointcut("execution(* com.probuing.springbootcros.service.*.* (..))")
    public void pc1() {

    }

    @Before(value = "pc1()")
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println(name + "方法开始执行");
    }

    @After(value = "pc1()")
    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println(name + "方法执行结束");
    }

    @AfterReturning(value = "pc1()", returning = "result")
    public void afterRunning(JoinPoint jp, Object result) {
        String name = jp.getSignature().getName();
        System.out.println(name + "方法返回值为" + result);
    }


    @AfterThrowing(value = "pc1()", throwing = "e")
    public void afterThrowing(JoinPoint jp, Exception e) {
        String name = jp.getSignature().getName();
        System.out.println(name + "方法异常了" + e.getMessage());
    }


    @Around(value = "pc1()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        return pjp.proceed();
    }

}
  • @Aspect表明这是一个切面类
  • @Pointcut 是切入点的定义,execution中的第一个表示方法返回任意值,第二个表示方法返回任意值,第二个* 表示service包下的任意类,第三个*表示类中的任意方法。括号中的两个点表示方法参数任意。这里的切点表达式表示切入点为service包下所有类中的所有方法
  • @Before表示这是一个前置哦通知,该方法在目标方法执行之前执行,通过JoinPoint参数可以获取目标方法的方法名,修饰符
  • @After表示这是一个后置通知,该方法在目标方法执行之后执行
  • @AfterReturning注解,表示这是一个返回通知,在该方法中可以获取目标方法的返回值。@AfterReturning注解的returning参数是指返回值的变量名,对应方法的参数。
  • @AfterThrowing,表示这是一个异常通知,即当目标方法发生异常时,该方法会被调用,异常类型为Exception表示所有的异常都会进入该方法中执行
  • @Around,表示这是一个环绕通知,环绕通知是所有通知里最强大的通知,可以实现前置通知、后置通知、异常通知以及返回通知的功能 目标方法进入环绕通知后,通过调用ProceedingJoinPoint对象的proceed方法使目标方法继续执行,开发者可以在此修改目标方法的执行参数、返回值等,并且可以在此处理目标方法的异常

其他设置

自定义欢迎页

SpringBoot项目在启动后,首先会去静态资源路径下查找index.html作为首页文件,若查找不到,则会去查找动态的index文件作为首页
如果使用静态的index.html作为项目首页,那么只需要在resources/static目录下创建index.html。如果使用动态页面作为项目首页则需要在resources/templates目录下创建index.html,然后在Controller中返回逻辑视图名。

自定义favicon

favicon.ico是浏览器选项卡左上角的图标,可以放在静态资源路径下或者类的路径下,静态资源路径下的favicon.ico优先级高于favicon.co
将图标文件复制到/resources/static 目录下



喜欢的朋友记得点赞、收藏、关注哦!!!

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

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

相关文章

为什么Modbus链接/从机不通?From 摩尔信使MThings

为了回应用户平日里关于摩尔信使&#xff08;MThings&#xff09;使用过程中最常见的问题&#xff0c;包括“网络链接连不上”、“为什么不能增加串口”和“为什么从机不通”&#xff0c;我们在此统一介绍解决方法。 1、具备哪些通信能力 支持串口和网络两种通信方式。 需要…

我们后端程序员不是操作MyBatis的CRUD Boy

大家好&#xff0c;我是南哥。 一个对Java程序员进阶成长颇有研究的人&#xff0c;今天我们接着新的一篇Java进阶指南。 为啥都戏称后端是CRUD Boy&#xff1f;难道就因为天天怼着数据库CRUD吗&#xff1f;要我说&#xff0c;是这个岗位的位置要的就是你CRUD&#xff0c;你不…

FastAPI教程II

本文参考FastAPI教程https://fastapi.tiangolo.com/zh/tutorial Cookie参数 定义Cookie参数与定义Query和Path参数一样。 具体步骤如下&#xff1a; 导入Cookie&#xff1a;from fastapi import Cookie声明Cookie参数&#xff0c;声明Cookie参数的方式与声明Query和Path参数…

Hi3861 OpenHarmony嵌入式应用入门--LiteOS MessageQueue

CMSIS 2.0接口中的消息&#xff08;Message&#xff09;功能主要涉及到实时操作系统&#xff08;RTOS&#xff09;中的线程间通信。在CMSIS 2.0标准中&#xff0c;消息通常是通过消息队列&#xff08;MessageQueue&#xff09;来进行处理的&#xff0c;以实现不同线程之间的信息…

650V 1200V 碳化硅MOS TO247 封装 内阻30毫欧 40 80毫欧

650V 1200V 碳化硅MOS TO247 封装 内阻30毫欧 40 80毫欧

Java的IO体系

目录 1、Java的IO体系2、IO的常用方法3、Java中为什么要分为字节流和字符流4、File和RandomAccessFile5、Java对象的序列化和反序列化6、缓冲流7、Java 的IO流中涉及哪些设计模式 1、Java的IO体系 IO 即为 input 输入 和 output输出 Java的IO体系主要分为字节流和字符流两大类…

MySQL中的redo log 和 undo log

undo log和redo log 先引入两个概念&#xff1a; 当我们做了一些操作 (update/delete/insert)&#xff0c;提交事务后要操作MySql中的数据。 为了能够提升性能&#xff0c;引入了两块区域&#xff1a;内存结构和磁盘结构。 磁盘结构&#xff1a; 主要存储的就是数据页&#x…

LeetCode 算法:二叉搜索树中第K小的元素 c++

原题链接&#x1f517;&#xff1a;二叉搜索树中第K小的元素 难度&#xff1a;中等⭐️⭐️ 题目 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从1开始计数&#xff09;。 示例 1&#xff1a;…

页面开发感想

页面开发 1、 前端预览 2、一些思路 2.1、首页自定义element-plus的走马灯 :deep(.el-carousel__arrow){border-radius: 0%;height: 10vh; }需要使用:deep(标签)才能修改样式 或者 ::v-deep 标签 2.2、整体设计思路 <template><div class"card" style&…

机器学习第四十五周周报 SAM优化器

文章目录 week45 SAM优化器摘要Abstract1. 题目2. Abstract3. 锐度感知最小化3.1 问题提出3.2 方法提出 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程 5. 结论6.代码复现小结参考文献 week45 SAM优化器 摘要 本周阅读了题为Sharpness-Aware Minimization for Efficien…

! Warning: `flutter` on your path resolves to

目录 项目场景&#xff1a; 问题描述 原因分析&#xff1a; 解决方案&#xff1a; 1. 检查并更新.bash_profile或.zshrc文件 2.添加Flutter路径到环境变量 3. 加载配置文件 4.验证Flutter路径 5.重新启动终端 项目场景&#xff1a; 今天重新安装了AndroidStudio,并配置…

Postman设置请求间自动保存返回参数,方便后续请求调用,减少复制粘贴

postman中常常出现&#xff1a;有两个请求&#xff0c;一个请求首先获取验证码或者token&#xff0c;再由得到的验证码或token编写body发送另一个请求。如何设置两个请求间自动关联相关数据呢&#xff1f; 通过环境存储全局变量 现在有两个请求如下图&#xff0c;生成验证码是…

如何制作鼠标悬浮后伸缩的搜索框

引言 许多博客都在使用的伸缩搜索框制作教程 成品展示&#xff08;颜色自行搭配&#xff09; 初步布局 居中盒子&&初始化样式 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewpo…

进程间通信简介-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

进程间通信简介 进程间通信简介 进程间进程简称IPC(interprocess communication)&#xff0c;进程间通信就是在不同进程之间传递信息或交换信息 进程间通信的目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的…

【Docker】集群容器监控和统计 CAdvisor+lnfluxDB+Granfana的基本用法

集群容器监控和统计组合&#xff1a;CAdvisorlnfluxDBGranfana介绍 CAdvisor&#xff1a;数据收集lnfluxDB&#xff1a;数据存储Granfana&#xff1a;数据展示 ‘三剑客’ 安装 通过使用compose容器编排&#xff0c;进行安装。特定目录下新建文件docker-compose.yml文件&am…

使用Vercel 搭建自己的Dashy导航页

背景 Dashy 是一个开源的自托管导航页面配置服务&#xff0c;它具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。用户可以利用 Dashy 将自己常用的一些网站聚合起来&#xff0c;形成一个个性化的导航页面。 同类的竞品还有Heimdall, Flare 等。 可以通过Docker 等…

uniapp,uni-fab组件拖动属性,替代方案

文章目录 1. 背景2. 替代方案2.1 方案一2.2 方案二参考1. 背景 最近基于uniapp开发一款设备参数调试的APP软件,其中有使用到悬浮按钮,快速开发阶段,为了能尽快上线,直接使用了uni-ui的扩展组件uni-fab,参考【1】,效果如下图: 后期,相应的界面内容增多,由于uni-fab是…

TS_类型

目录 1.类型注解 2.类型检查 3.类型推断 4.类型断言 ①尖括号&#xff08;<>&#xff09;语法 ②as语法 5.数据类型 ①boolean ②number ③string ④undefined 和 null ⑤数组和元组 ⑥枚举 ⑦any 和void ⑧symbol ⑨Function ⑩Object 和 object 6.高…

在晋升受阻或遭受不公待遇申诉时,这样写是不是好一些?

在晋升受阻或遭受不公待遇申诉时&#xff0c;这样写是不是好一些&#xff1f; 在职场中&#xff0c;晋升受阻或遭受不公待遇是员工可能面临的问题之一。面对这样的情况&#xff0c;如何撰写一份有效的申诉材料&#xff0c;以维护自己的合法权益&#xff0c;就显得尤为重要。#李…

mathcup大数据竞赛论文中集成学习(或模型融合)的运用分析

ps: (模型融合和集成学习是两个紧密相关但又有所区别的概念。集成学习是一种更广泛的范式&#xff0c;而模型融合可以被视为集成学习的一种特殊形式或策略。) 1.集成学习原理 图1 如图1所示&#xff0c;集成学习是一种通过结合多个机器学习模型的预测来提高整体性能的策略。其…