Swagger在php和java项目中的应用

news2024/11/17 6:52:01

Swagger在php和java项目中的应用

  • Swagger简介
  • Swagger在java项目中的应用
    • 步骤
    • 常用注解
  • Swagger在php项目中的应用

Swagger简介

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。

总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。Swagger 让部署管理和使用功能强大的 API 从未如此简单。

  • 对于后端开发人员来说
  1. 不用再手写WiKi接口拼大量的参数,避免手写错误
  2. 对代码侵入性低,采用全注解的方式,开发简单
  3. 方法参数名修改、增加、减少参数都可以直接生效,不用手动维护
  4. 增加了开发成本,写接口还得再写一套参数配置
  • 对于前端开发来说
  1. 后端只需要定义好接口,会自动生成文档,接口功能、参数一目了然
  2. 联调方便,如果出问题,直接测试接口,实时检查参数和返回值,就可以快速定位是前端还是后端的问题
  • 对于测试来说
  1. 对于某些没有前端界面UI的功能,可以用它来测试接口
  2. 操作简单,不用了解具体代码就可以操作

Swagger在java项目中的应用

knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案

步骤

  1. 导入knife4j的maven坐标
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.2</version>
</dependency>
  1. 导入knife4j相关配置类(WebMvcConfig)
  2. 设置静态资源,否则接口文档页面无法访问
package com.demo.config;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.List;

@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * 设置静态资源映射
     * @param registry
     */
    protected void addResourceHandlers (ResourceHandlerRegistry registry) {    				
    	registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    @Bean
    public Docket createRestApi () {
        // 文档类型
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.demo.controller")) // swagger扫描的包
                .paths(PathSelectors.any())
                .build();
    }

	/**
	* 介绍接口信息
	*/
    private ApiInfo apiInfo () {
        return new ApiInfoBuilder()
                .title("Robin's Swagger documents")
                .version("1.0")
                .description("Robin's Swagger documents")
                .build();
    }
}

  1. 在LoginCheckFilter中设置不需要处理的请求路径
package com.demo.filter;

import com.alibaba.fastjson.JSON;
import com.demo.common.BaseContext;
import com.demo.common.R;
import com.demo.entity.Employee;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 检查用户是否已经完成登录
 */

@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
public class LoginCheckFilter implements Filter {

    // 路径匹配器,支持通配符
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    // 定义不需要处理的请求路径
    public static final String[] urls = new String[]{
            "/employee/login", // 登录接口
            "/employee/logout", // 退出接口
            "/backend/**", // 放行后台静态资源
            "/front/**", // 放行前台静态资源
            "/common/download", // 文件下载接口
            "/user/login", // 移动端登录
            "/user/sendMsg", // 获取验证码接口
            "/doc.html", // swagger文档路径
            "/webjars/**",
            "/swagger-resources/**",
            "/v2/api-docs",
    };

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 1、获取本次请求的URI
        String requestUri = request.getRequestURI();

        // 2、判断本次请求是否需要处理,如果不需要处理,则直接放行
        if (check(requestUri)) {
            filterChain.doFilter(request, response);
            return;
        }

        // 3、判断登录状态,如果已登录,则直接放行
        Long empId = (Long) request.getSession().getAttribute("employee");
        Long userId = (Long) request.getSession().getAttribute("user");
        if (empId != null || userId != null) {
            // 将当前登录的用户id保存到ThreadLocal中
            if (empId != null) BaseContext.setCurrentId(empId);
            if (userId != null) BaseContext.setCurrentId(userId);
            filterChain.doFilter(request, response);
            return;
        }

        // 4、如果未登录,则返回未登录结果
        log.info("拦截到请求:{}", request.getRequestURI());
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
    }

    /**
     * 路径匹配,检测本次请求是否需要放行
     * @param requestUri 本次请求资源
     * @return 路径匹配结果,true-放行,false-不放行
     */
    public boolean check (String requestUri) {
        for (String url:urls) {
            if (PATH_MATCHER.match(url, requestUri)) {
                return true;
            }
        }
        return false;
    }
}

访问域名/doc.html,在这里插入图片描述

常用注解

注解说明
@Api用在请求的类上,例如Controller,表示对类的说明
@ApiModel用在类上,通常是实体类,表示一个返回响应数据的信息
@ApiModelProperty用在属性上,描述响应类的属性
@ApiOperation用在请求的方法上,说明方法的用途、作用
@ApiImplicitParams用在请求的方法上,表示一组参数说明
@ApiImplicitParam用在@ApilmplicitParams 注解中,指定一个请示参数的各个方面

R实体类补充注解:

package com.demo.common;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * 通用返回结果,服务端响应的数据最终都会封装成此对象
 * @param <T>
 */
@Data
@ApiModel("返回结果")
public class R<T> implements Serializable {

    @ApiModelProperty("编码:1成功,0和其它数字为失败")
    private Integer code; //编码:1成功,0和其它数字为失败

    @ApiModelProperty("错误信息")
    private String msg; //错误信息

    @ApiModelProperty("数据")
    private T data; //数据

    @ApiModelProperty("动态数据")
    private Map map = new HashMap(); //动态数据

    public static <T> R<T> success(T object) {
        R<T> r = new R<T>();
        r.data = object;
        r.code = 1;
        return r;
    }

    public static <T> R<T> error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }

    public R<T> add(String key, Object value) {
        this.map.put(key, value);
        return this;
    }

}

套餐实体类补充注解:

package com.demo.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 套餐
 */
@Data
@ApiModel("套餐")
public class Setmeal implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty("主键")
    private Long id;


    //分类id
    @ApiModelProperty("分类id")
    private Long categoryId;


    //套餐名称
    @ApiModelProperty("套餐名称")
    private String name;


    //套餐价格
    @ApiModelProperty("套餐价格")
    private BigDecimal price;


    //状态 0:停用 1:启用
    @ApiModelProperty("状态 0:停用 1:启用")
    private Integer status;


    //编码
    @ApiModelProperty("编码")
    private String code;


    //描述信息
    @ApiModelProperty("描述信息")
    private String description;


    //图片
    @ApiModelProperty("图片")
    private String image;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT)
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

    //是否删除
    @ApiModelProperty("是否删除")
    private Integer isDeleted;
}

套餐接口补充注解:

package com.demo.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.demo.common.R;
import com.demo.dto.SetmealDto;
import com.demo.entity.Category;
import com.demo.entity.Setmeal;
import com.demo.service.CategoryService;
import com.demo.service.SetmealDishService;
import com.demo.service.SetmealService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 套餐管理
 */
@Slf4j
@RestController
@RequestMapping("/setmeal")
@Api(tags = "套餐相关接口")
public class SetmealController {

    @Autowired
    private SetmealService setmealService;

    @Autowired
    private SetmealDishService setmealDishService;

    @Autowired
    private CategoryService categoryService;

    /**
     * 新增套餐
     * @param setmealDto 套餐实体
     * @return 返回信息
     */
    @CacheEvict(value = "setmealCache", allEntries = true)
    @PostMapping
    @ApiOperation(value = "新增套餐接口")
    public R<String> save(@RequestBody SetmealDto setmealDto) {
        setmealService.saveWithDish(setmealDto);
        return R.success("新增套餐成功");
    }

    /**
     * 套餐分页查询
     * @param page 页码
     * @param pageSize 单页数据量
     * @param name 套餐名称
     * @return 列表数据
     */
    @GetMapping("/page")
    @ApiOperation(value = "套餐分页查询")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "页码", required = true),
            @ApiImplicitParam(name = "pageSize", value = "每页记录数", required = true),
            @ApiImplicitParam(name = "name", value = "套餐名称", required = false),
    })
    public R<Page<SetmealDto>> page (int page, int pageSize, String name) {
        // 构建分页构造器
        Page<Setmeal> pageInfo = new Page<>(page, pageSize);

        LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件,根据name进行模糊查询
        lambdaQueryWrapper.like(name != null, Setmeal::getName, name);
        // 添加排序条件,根据更新时间降序排列
        lambdaQueryWrapper.orderByAsc(Setmeal::getStatus).orderByDesc(Setmeal::getUpdateTime);
        setmealService.page(pageInfo, lambdaQueryWrapper);

        // 对象拷贝,补充分类信息
        Page<SetmealDto> dtoPage = new Page<>(page, pageSize);
        BeanUtils.copyProperties(pageInfo, dtoPage, "'records'");
        List<Setmeal> records = pageInfo.getRecords();
        List<SetmealDto> list = records.stream().map(
                (item) -> {
                    // 对象拷贝
                    SetmealDto setmealDto = new SetmealDto();
                    BeanUtils.copyProperties(item, setmealDto);
                    // 设置分类名称
                    Category category = categoryService.getById(item.getCategoryId());
                    if (category != null) {
                        setmealDto.setCategoryName(category.getName());
                    }
                    return setmealDto;
                }
        ).collect(Collectors.toList());

        dtoPage.setRecords(list);
        return R.success(dtoPage);
    }

    /**
     * 批量删除套餐
     * @param ids 套餐id
     * @return 返回信息
     */
    @CacheEvict(value = "setmealCache", allEntries = true)
    @DeleteMapping
    @ApiOperation(value = "批量删除套餐")
    public R<String> delete(@RequestParam List<Long> ids) {
        setmealService.removeWithDish(ids);
        return R.success("套餐数据删除成功");
    }

    /**
     * 批量上下架
     * @param ids 套餐id
     * @param status 上下架状态
     * @return 返回信息
     */
    @PostMapping("/status/{status}")
    @ApiOperation(value = "批量上下架")
    public R<String> updateStatus(@RequestParam List<Long> ids, @PathVariable int status) {
        List<Setmeal> setmealList = ids.stream().map(
                (item) -> {
                    Setmeal setmeal = new Setmeal();
                    setmeal.setId(item);
                    setmeal.setStatus(status);
                    return setmeal;
                }
        ).collect(Collectors.toList());
        setmealService.updateBatchById(setmealList);
        return R.success("更新成功");
    }

    /**
     * 获取套餐详情数据
     * @param id 套餐id
     * @return 套餐实体信息
     */
    @GetMapping("/{id}")
    @ApiOperation(value = "获取套餐详情数据")
    public R<SetmealDto> detail(@PathVariable Long id) {
        SetmealDto setmealDto = setmealService.getSetmealWithDish(id);
        return R.success(setmealDto);
    }

    /**
     * 修改套餐
     * @param setmealDto 套餐实体
     * @return 舞台信息
     */
    @PutMapping
    @ApiOperation(value = "修改套餐")
    public R<String> update(@RequestBody SetmealDto setmealDto) {
        setmealService.updateWithDish(setmealDto);
        return R.success("编辑成功");
    }

    /**
     * 根据条件查询套餐数据
     * @param setmeal 套餐过滤条件
     * @return 套餐列表
     */
    @GetMapping("/list")
    @Cacheable(value = "setmealCache", key="#setmeal.categoryId + '_' + #setmeal.status", unless = "#result.data.size() == 0")
    @ApiOperation(value = "根据条件查询套餐数据")
    public R<List<Setmeal>> list(Setmeal setmeal) {
        log.info("未命中缓存查询");
        LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 分类条件
        lambdaQueryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());
        // 上下架状态
        lambdaQueryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());
        // 排序
        lambdaQueryWrapper.orderByDesc(Setmeal::getUpdateTime);
        List<Setmeal> list = setmealService.list(lambdaQueryWrapper);
        return R.success(list);
    }
}

重新启动服务,查看实体和接口文档

在这里插入图片描述
在这里插入图片描述

Swagger在php项目中的应用

  1. 安装swagger包

zircote/swagger-php是swagger的php版,是一个扩展库,可以通过composer来进行安装

composer require zircote/swagger-php
  1. 安装Swagger ui

将swagger-ui下载下来以后,把dist目录下的文件复制到项目public/docs目录下, 这个目录可以自定义, 通俗来讲就是放到项目能访问到的目录下, 然后再将dist目录下的swagger-initializer.js文件中的url改成./openapi.yaml, 这里的openapi.yaml是生成文档后的文件名,意思是访问本地的openapi.yaml文件

在这里插入图片描述

<?php
namespace app\controller;

use app\BaseController;
use think\App;
use think\facade\Request;

/**
 * @OA\Info (
 *     title = "Robins's API documetns",
 *     version = "1.0",
 *     description="本文档仅限于测试"
 * )
 */
class Index extends BaseController
{


    public function getDoc() {
        $openapi = \OpenApi\Generator::scan([__ROOT__ . '/../app']);
        // 生成yaml文件
        file_put_contents(__ROOT__ . '\doc\dist\openapi.yaml', $openapi->toYaml());
    }

    /**
     * @OA\Get (
     *     path="/",
     *     tags = {"用户订单列表接口"},
     *     summary = "用户订单列表接口",
     *     description = "获取用户订单信息",
     *     @OA\Parameter (name = "order_id", in = "query", description = "订单号", required = true),
     *     @OA\Parameter (name = "account_id", in = "query", description = "账户id", required = true),
     *     @OA\Response(response = "200",description = "The data"),
     *     @OA\MediaType(
     *          mediaType="application/json",
     *          @OA\Schema(ref="#/components/schemas/Info"),
     *     )
     * )
     * @return \think\response\Json
     */
    public function index()
    {      
        $accountId = Request::post('account_id', 0);       
        $orderId = Request::post('order_id', '');       
     	$data = Order::where(['account_id' => $accountId, 'order_id' => $orderId])->select()->toArray();
        return json($data);
    }
}

swagger在php项目中的注解还需要一点点摸索熟练

在这里插入图片描述

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

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

相关文章

Windows环境搭建

Windows环境搭建 一. jdk1.8安装1. 资源链接2. 安装3. 配置环境变量 一. jdk1.8安装 1. 资源链接 资源链接 提取码&#xff1a;tfms 2. 安装 1.双击下载好的JDK,点击下一步。 2.修改默认目录&#xff08;可不修改&#xff09;&#xff0c;点击下一步&#xff0c; 3. 点击下…

Matplotlib图形配置与样式表_Python数据分析与可视化

Matplotlib图形配置与样式表 配置图形修改默认配置rcParams样式表 Matplotlib的默认图形设置经常被用户诟病。虽然2.0版本已经有了很大改善&#xff0c;但是掌握自定义配置的方法可以让我们打造自己的艺术风格。 配置图形 我们可以通过修个单个图形配置&#xff0c;使得最终图…

CH01_适应设计模式

Iterator模式&#xff08;迭代器模式&#xff09; 迭代器模式&#xff08;Iterator&#xff09;,提供一种方法&#xff0c;顺序访问一个聚合对象中各个元素&#xff0c;而不是暴露该对象的内部表示。 类图结构 说明 Iterator&#xff08;迭代器&#xff09; 该角色负责定义按…

洛谷P1049装箱问题 ————递归+剪枝+回溯

没没没没没没没没没错&#xff0c;又是一道简单的递归&#xff0c;只不过加了剪枝&#xff0c;我已经不想再多说&#xff0c;这道题写了一开始写了普通深搜&#xff0c;然后tle了一个点&#xff0c;后面改成剪枝&#xff0c;就ac了&#xff0c;虽然数据很水&#xff0c;但是不妨…

基于光纤环形激光器的optisystem仿真及其传感应用

近年来&#xff0c;光纤传感器在航空航天领域&#xff0c;工业制造&#xff0c;医疗等领域引起了越来越多的关注&#xff0c;因为他们体积小&#xff0c;结构简单&#xff0c;灵敏度高&#xff0c;抗电磁干扰强&#xff0c;防腐性能好的特点。各种各样的传感器结构被设计出来&a…

VMware Workstation Pro 安装虚拟机,无法打开此虚拟机电源 因为它需要使用x86架构,架构冲突

本来我下的iso文件&#xff0c;可以看到他是64的&#xff0c;但是ubuntu没有86的&#xff0c;我只能去下载cenos的 用这个去安装虚拟机就好了

在 vue3 中使用 Recorder 实现录音并上传(mp3、wav)兼容 PC 和移动端

一、Recorder 介绍 使用 Recorder插件可以在网页中进行录音。生成 blob 文件并可以自定义上传&#xff0c;同时&#xff0c;录音过程中会显示可视化波形&#xff0c;同时能够做到兼容PC端、Android、和iOS&#xff0c;十分好用&#xff01; Recorder github 首页 插件效果展…

深入理解MySQL索引及事务

✏️✏️✏️今天给各位带来的是关于数据库索引以及事务方面的基础知识 清风的CSDN博客 &#x1f61b;&#x1f61b;&#x1f61b;希望我的文章能对你有所帮助&#xff0c;有不足的地方还请各位看官多多指教&#xff0c;大家一起学习交流&#xff01; 动动你们发财的小手&#…

[Docker]十一.Docker Swarm集群raft算法,Docker Swarm Web管理工具

一.Docker Swarm集群raft算法讲解 Raft &#xff1a;一致性算法&#xff0c;在保证大多数管理节点存活的情况下&#xff0c;集群才能使用&#xff0c; 所以就要求如果集群的话&#xff0c; manager 节点必须 >3 台 &#xff0c;如果是两个台&#xff0c;其中一台宕机&#…

安卓 Android Studio更换app的图标

大概完成了一个app&#xff0c;在测试机的界面app的icon显示的是默认安卓图标&#xff0c;找了一个简单的更换方法 打开 Androidmanifest.xml 文件&#xff0c;在 application 找到代码 android:icon"mipmap/ic_launcher" 按下Ctrl鼠标左键转到相应位置 如图在背景…

BUUCTF [GXYCTF2019]gakki 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 得到的 flag 请包上 flag{} 提交。 密文&#xff1a; 下载附件&#xff0c;解压得到一张.jpg图片。 解题思路&#xff1a; 1、放到010 Editor中看一下&#xff0c;找到rar压缩包的文件头。使用Kali中的binwalk工具…

selenium的基础语法

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️山水速疾来去易&#xff0c;襄樊镇固永难开 ☁️定位页面的元素 参数:抽象类By里…

迈巴赫S480升级电动后门 手势控制开关 更加方便

安装了电动后门的迈巴赫S480&#xff0c;从原来的触摸门把手和门内拉手开关门&#xff0c;增加了钥匙控制、前排显示屏控制、后门按键开关控制、后排娱乐屏控制等多种开关门方式&#xff0c;将一个待客之礼体现出多种不一样的尊贵感受。 中控显示屏由驾驶者控制&#xff0c;可以…

ruoyi-plus-vue docker 部署

本文以 ruoyi-vue-plus 5.x docker 部署为基础 安装虚拟机 部署文档 安装docker 安装docker 安装docker-compose 配置idea环境 上传 /doicker 文件夹 到服务器&#xff1b;赋值 777权限 chmod -R 777 /docker idea构建 jar 包 利用 idea 构建镜像; 创建基础服务 docker…

[SWPUCTF 2021 新生赛]PseudoProtocols

题目很明确了就是伪协议 php://filter/convert.base64-encode/resourcehint.php 提交的伪协议的内容需要是 I want flag&#xff0c;就会echo flag 方法1&#xff1a;adata://text/plain,I want flag 方法2&#xff1a;adata://text/plain;base64,SSB3YW50IGZsYWc

NET 8.0 中新的变化

1性能提升 .NET 8在整个堆栈中带来了数千项性能改进 。默认情况下会启用一种名为动态配置文件引导优化 (PGO) 的新代码生成器&#xff0c;它可以根据实际使用情况优化代码&#xff0c;并且可以将应用程序的性能提高高达 20%。现在支持的 AVX-512 指令集能够对 512 位数据向量执…

从零开始学优惠券样式代码编写,让你的网站焕然一新!

样式1&#xff1a; 代码实例&#xff1a; <div class"box"><div class"itemBox"><div class"leftBox">全额抵扣</div><div class"rightBotton"><button>立即使用</button></div><…

Mac开发环境——MacOSX安装与配置Anaconda与PyCharm详细流程

一、安装与使用Anaconda 1.简介 Anaconda 是一个用于数据科学、机器学习和科学计算的开源发行版和包管理器。有许多可用于数据处理、分析和建模的工具和库&#xff0c;并提供了一个方便的环境管理系统。Anaconda 包含了 Python 解释器和许多常用的 Python 包&#xff0c;以及…

自动化部署 / 扩容openGauss —— Ansible for openGauss

前言 大家好&#xff0c;今天我们为大家推荐一套基于 Ansible 开发的&#xff0c;自动化部署及扩容 openGauss 的脚本工具&#xff1a;Ansible for openGauss&#xff08;以下简称 AFO&#xff09;。 通过AFO&#xff0c;我们只需简单修改一些配置文件&#xff0c;即可快速部署…

c++数学表达式解析求值库推荐

让程序支持自定义的数学计算器是常用功能&#xff0c;找了几个用来数学表达式解析求值的库&#xff0c;有几个看起来很不错。 各个数学表达式求值的综合对比 对比结果如下&#xff0c;ExprTK得分最高&#xff0c; TinyExpr得分最低&#xff0c; GitHub - ArashPartow/math-par…