Java单体架构项目_云霄外卖-特殊点

项目介绍:

定位:

        专门为餐饮企业(餐厅、饭店)定制的一款软件商品

分为:

        管理端:外卖商家使用

        用户端(微信小程序):点餐用户使用。

功能架构:

(体现项目中的业务功能模块)

技术选型:

(展示项目中使用到的技术框架和中间件等)

环境搭建

整体架构:

前端:

        管理端使用nginx,使用已经打包好的前端代码,并且Nginx的配置文件中已经配置了反向代理,通过此配置可以将前端请求转发到后端服务。

        用户端之后再做介绍

后端:

后端框架:

  

1.sky-common子模块中存放的是一些工具类,可以供其他模块使用

2.sky-pojo子模块中存放的是一些entity(实体类),DTO,VO

3.sky-server子模块中存放的是配置文件、配置类、拦截器、controller、service、mapper、启动类等

版本控制

        使用Git进行版本控制

数据库:

前后端联调:

        使用nginx反向代理:

nginx反向代理:

好处:

使用方法:

接口文档:

前后端分离开发流程:

设计阶段:

Apifox:

        Apifox是设计阶段使用的工具,管理和维护接口。

开发阶段:

Swagger:

        Swagger是在开发阶段使用的框架,帮助后端开发人员做后端的接口测试

介绍:

使用方式:

1.

2.

3.

常用注解:

管理端业务功能编写:

登录功能:

        完善登录功能使用MD5对数据加密

员工管理:

添加员工:

        添加员工时通过ThreadLocal获取执行人id和创建人id

ThreadLocal介绍:

        并且客户端发起的每一次请求都是一个单独的线程,这样就满足使用ThreadLocal的条件。

ThreadLocal常用方法:

员工分页查询:

        调整LocalDataTime类型数据响应回去的格式

        推荐第二种,只需要一次编码就可以调整全部指定内容

操作过程:

1.新建一个对象映射器:

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    //public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}

2.在配置类中添加如下代码:

    /**
     * 扩展MVC框架的消息转换器
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("开始扩展消息转换器");

        //创建一个消息转换器对象
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();

        //设置对象转换器,可以将java对象转为json对象
        converter.setObjectMapper(new JacksonObjectMapper());

        //将自己的转换器放入spring MVC框架的容器中,并放到0索引位置,排到第一个,这样一定会使用它
        converters.add(0, converter);
    }

公共字段自动填充:

枚举类:

/**
 * 数据库操作类型
 */
public enum OperationType {

    /**
     * 更新操作
     */
    UPDATE,

    /**
     * 插入操作
     */
    INSERT

}

自定义注解:

/**
 * 自定义注解,用于标识需要进行公共字段自动填充的方法
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {

    /**
     * 枚举类 自定义数据库操作类型insert和update操作
     * @return
     */
    OperationType value();

}

自定义切面类:

/**
 * 自定义切面,实现公共字段自动填充处理逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {}

    /**
     * 前置通知,为公共字段赋值
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段填充...");
        //获取到当前被拦截方法上的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解
        OperationType operationType = autoFill.value();//获得数据库操作类型

        //获取到当前被拦截方法的参数--实体对象
        Object[] args = joinPoint.getArgs();
        Object entity = args[0];

        //准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        //根据当前不同的操作类型,为对应的属性通过反射来赋值
        if(operationType == OperationType.INSERT) {
            try {
                Method setCreateTime = entity.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                setCreateTime.invoke(entity,now);
                setCreateUser.invoke(entity,currentId);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if(operationType == OperationType.UPDATE) {
            try {
                Method setUpdateTime = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

}

给mapper层的insert和update数据库操作类型添加自定义的注解:

        @AutoFill(OperationType.UPDATE)或@AutoFill(OperationType.INSERT)

注意点:

        ·在菜品分页查询部分,可能传来的参数:status状态在动态SQL里不能只能判断其为null,不能加上and status = '',这样会一直读取不到它,具体原因不清楚。

        ·<set>标签下的<if>标签中的内容记得加逗号

操作Redis:

        想要了解Redis的基础知识及使用方法可以参考作者另一边文章《Java_中间件——Redis》

Redis的Java客户端:

        下面我们使用Spring Data Redis来操作Redis

Spring Data Redis使用方式:

配置类RedisTemplate:

@Configuration
@Slf4j
public class RedisConfiguration {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        log.info("开始创建redis模板对象...");
        RedisTemplate redisTemplate = new RedisTemplate();
        //设置redis连接工厂对象
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置redis key的序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }

}

代码演示:

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testRedisTemplate() {
        System.out.println(redisTemplate);
        //操作字符串
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //操作Hash
        HashOperations hashOperations = redisTemplate.opsForHash();
        //操作List
        ListOperations listOperations = redisTemplate.opsForList();
        //操作set
        SetOperations setOperations = redisTemplate.opsForSet();
        //操作有序集合
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();

    }

    /**
     * 操作字符串类型的数据
     */
    @Test
    public void testStirng() {
        // set get setex setnx
        redisTemplate.opsForValue().set("city","北京");
        String city = (String) redisTemplate.opsForValue().get("city");
        System.out.println(city);
        redisTemplate.opsForValue().set("code","6562",60, TimeUnit.SECONDS);
        redisTemplate.opsForValue().setIfAbsent("lock","1");
        redisTemplate.opsForValue().setIfAbsent("lock","2");
    }

    /**
     * 操作哈希类型的数据
     */
    @Test
    public void testHash() {
        //hset hget hdel hkeys hvals
        HashOperations hashOperations = redisTemplate.opsForHash();

        hashOperations.put("100","name","xiaobai");
        hashOperations.put("100","age","20");

        String name = (String) hashOperations.get("100", "name");
        System.out.println(name);

        Set keys = hashOperations.keys("100");
        System.out.println(keys);

        List values = hashOperations.values("100");
        System.out.println(values);

        hashOperations.delete("100","age");
    }

    /**
     * 操作列表类型的数据
     */
    @Test
    public void testList() {
        // lpush lrange rpop llen
        ListOperations listOperations = redisTemplate.opsForList();

        listOperations.leftPushAll("mylist","a","b","c");
        listOperations.leftPush("mylist","d");

        List mylist = listOperations.range("mylist", 0, -1);
        System.out.println(mylist);

        listOperations.rightPop("mylist");

        Long size = listOperations.size("mylist");
        System.out.println(size);

    }

    /**
     * 操作集合类型的数据
     */
    @Test
    public void testSet() {
        // sadd smembers scard sinter sunion srem
        SetOperations setOperations = redisTemplate.opsForSet();

        setOperations.add("set1","a","b","c");
        setOperations.add("set2","b","c","d");

        Set set1 = setOperations.members("set1");
        System.out.println(set1);

        Long size = setOperations.size("set1");
        System.out.println(size);

        Set intersect = setOperations.intersect("set1", "set2");
        System.out.println(intersect);

        Set union = setOperations.union("set1", "set2");
        System.out.println(union);

        setOperations.remove("set1","a","b");

    }

    /**
     * 操作有序集合类型的数据
     */
    @Test
    public void testZSet() {
        // zadd zrange zincrby zrem
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();

        zSetOperations.add("zset1","a",10);
        zSetOperations.add("zset1","b",11);
        zSetOperations.add("zset1","c",9);

        Set zset1 = zSetOperations.range("zset1", 0, -1);
        System.out.println(zset1);

        zSetOperations.incrementScore("zset1","c",10);

        zSetOperations.remove("zset1","a","b");
    }

    /**
     * 通用命令操作
     */
    @Test
    public void testCommon() {
        // keys exists type del
        Set keys = redisTemplate.keys("*");
        System.out.println(keys);

        Boolean name = redisTemplate.hasKey("name");
        Boolean set1 = redisTemplate.hasKey("set1");

        for (Object key : keys) {
            DataType type = redisTemplate.type(key);
            System.out.println(type.name());
        }

        redisTemplate.delete("mylist");

    }

店铺营业状态设置:

        基于Redis的字符串来进行存储

        

        1表示营业,0表示打样

代码演示:

管理端设置营业状态、获取营业状态

@RequestMapping("/admin/shop")
@RestController("adminShopController")
@Slf4j
@Api(tags = "店铺相关接口")
public class ShopController {

    public static final String KEY = "SHOP_STATUS";

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 设置店铺的营业状态
     * @param status
     * @return
     */
    @PutMapping("/{status}")
    @ApiOperation("设置营业状态")
    public Result setStatus(@PathVariable Integer status) {
        redisTemplate.opsForValue().set(KEY,status);
        log.info("设置当前营业状态为:{}",status == 1 ? "营业中" : "打烊中");
        return Result.success();
    }

    @GetMapping("/status")
    @ApiOperation("管理端获取营业状态")
    public Result<Integer> getStatus() {
        Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
        log.info("当前的营业状态为:{}",status == 1 ? "营业中":"打烊中");
        return Result.success(status);
    }

}

用户端获取营业状态

@RequestMapping("/user/shop")
@RestController("userShopController")
@Slf4j
@Api(tags = "店铺相关接口")
public class ShopController {

    public static final String KEY = "SHOP_STATUS";

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/status")
    @ApiOperation("用户端获取营业状态")
    public Result<Integer> getStatus() {
        Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
        log.info("当前的营业状态为:{}",status == 1 ? "营业中":"打烊中");
        return Result.success(status);
    }

}

HttpClient

使用HttpCilent需要导入依赖:

(如果导入了阿里云OSS的依赖就不需要导入了,因为这个依赖中已经包含了这个依赖)

核心API:

发送请求步骤:

代码演示:

    /**
     * 测试通过HttpClient发送GET方式的请求
     */
    @Test
    public void testGET() throws Exception {
       //创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //创建请求对象
        HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status");

        //发送请求,接收响应结果
        CloseableHttpResponse response = httpClient.execute(httpGet);

        //解析结果
        //获取服务端返回的状态码
        int statusCode = response.getStatusLine().getStatusCode();
        System.out.println("服务端返回的状态码为:" + statusCode);
        //获取服务端返回数据
        HttpEntity entity = response.getEntity();
        String body = EntityUtils.toString(entity);
        System.out.println("服务端返回的数据为:" + body);

        //关闭资源
        response.close();
        httpClient.close();

    }

    /**
     * 测试通过HttpClient发送GET方式的请求
     */
    @Test
    public void testPOST() throws Exception {
        //创建HttpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //创建请求对象
        HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("username", "admin");
        jsonObject.put("password", "123456");
        StringEntity entity = new StringEntity(jsonObject.toString());
        //指定请求编码方式
        entity.setContentEncoding("UTF-8");
        //指定数据格式
        entity.setContentType("application/json");
        httpPost.setEntity(entity);

        //发送请求
        CloseableHttpResponse response = httpClient.execute(httpPost);

        //解析返回结果
        int statusCode = response.getStatusLine().getStatusCode();
        System.out.println("响应码为:" + statusCode);
        HttpEntity entity1 = response.getEntity();
        String body = EntityUtils.toString(entity1);
        System.out.println("响应数据为:" + body);

        //关闭资源
        response.close();
        httpClient.close();

    }

用户端微信小程序开发:

小程序目录结构:

主体:

页面:

微信登录过程:

Redis缓存菜品、套餐

原因:

        使用数据库一直查找会导致系统响应慢、用户体验差。所以使用Redis缓存。

缓存菜品:

实现思路:

Spring Cache:

常用注解:

                                                                                                                     (cacheName::key)↑

@Cacheable注解在方法执行前会通过动态代理,代理出一个Controller对象,然后判断缓存中是否有数据,如果有,则直接返回缓存数据,不再执行方法,如果没有,就会通过反射来调用方法。

删除全部:

Spring Task

定位:

        定时任务框架

cron表达式:

        注意:日和周只能一个填数值一个填?

        使用Spring Task对超时订单和一直配送中的订单进行处理

WebSocket

介绍:

应用场景:

        ·视频弹幕

        ·网页聊天

        ·体育实况更新

        ·股票基金报价实时更新

实现步骤:

       

         使用WebSocket来完成来单提醒和客户催单功能。

设计:

Apache POI

介绍:

应用场景:

创新点:

        1.用户端根据分类id查看菜品:通过在service、mapper层添加获取在售(status=1)商品/套餐方法,替代通过创建实体类对象进行list方法查找,将查询时间由5~17ms变为4~7ms。

        2.将工作台订单数据使用redis存储,实时更新。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

哎呀呀 又迟到了,还被抓住了,面面相觑 害怕

网络编程 我应该迟点来&#xff0c;唠嗑到35嘿嘿 心疼自己早起呜呜呜&#xff0c;幸运的是35开讲 计算机网络 分4层 应用层&#xff08;Application Layer&#xff09;&#xff1a; 应用层是用户接口和网络应用程序的接口。它允许用户访问网络服务&#xff0c;并支持各种应用程…

Windows系统下文件夹权限详解

文章目录 问题描述文件夹属性 问题描述 今天在Win10系统下&#xff0c;实现文件夹设置权限&#xff0c;具体的方案的涉及到我们公司内部的一款加密软件&#xff0c;不太方便透漏&#xff0c;借此机会&#xff0c;我也重新的回顾下windows系统下的文件夹权限 文件夹属性 打开…

[C++][设计模式][中介者模式]详细讲解

目录 1.动机2.模式定义3.要点总结 1.动机 在软件构建过程中&#xff0c;经常会出现多个对象相互关联的情况&#xff0c;对象之间常常会维持一种复杂的引用关系&#xff0c;如果遇到一些需求的更改&#xff0c;这种直接的引用关系将面临不断的变化在这种情况下&#xff0c;可以…

【小沐学AI】Python实现语音识别(whisper+HuggingFace)

文章目录 1、简介1.1 whisper 2、HuggingFace2.1 安装transformers2.2 Pipeline 简介2.3 Tasks 简介2.3.1 sentiment-analysis2.3.2 zero-shot-classification2.3.3 text-generation2.3.4 fill-mask2.3.5 ner2.3.6 question-answering2.3.7 summarization2.3.8 translation 3、…

PyTorch Tensor进阶操作指南(二):深度学习中的关键技巧

本文主要讲tensor的裁剪、索引、降维和增维 Tensor与numpy互转、Tensor运算等&#xff0c;请看这篇文章 目录 9.1、首先看torch.squeeze()函数&#xff1a; 示例9.1&#xff1a;&#xff08;基本的使用&#xff09; 小技巧1&#xff1a;如何看维数 示例9.2&#xff1a;&a…

ISO15765-2 道路车辆——通过控制器局域网(CAN)进行诊断通信 (翻译版)(万字长文)

ISO15765-2 道路车辆——通过控制器局域网&#xff08;CAN&#xff09;进行诊断通信 (翻译版)(万字长文) 文章目录 ISO15765-2 道路车辆——通过控制器局域网&#xff08;CAN&#xff09;进行诊断通信 (翻译版)(万字长文)第二部分&#xff1a;传输协议和网络层服务前言Foreword…

在navicat对mysql声明无符号字段

1.无符号设置 在 MySQL 中&#xff0c;我们可以使用 UNSIGNED 属性来设置列的无符号属性&#xff0c;这意味着该列只能存储非负整数值。对于一些需要存储正整数的列&#xff0c;比如年龄、数量等&#xff0c;使用 UNSIGNED 属性可以提高数据存储和查询的效率&#xff0c;并且能…

浅谈一下VScode如何配置C环境

1.这几天突然发现在VScode写C程序比在DevC效果更好&#xff0c;因为在VScode中写代码有代码补全功能。所以我突然对在VScode中配置C环境变量产生了兴趣。 2.不过在VScode中配置C环境要是按照官方的来配置有点麻烦。 3.我这里有一个直接配置VScode中C环境变量的应用。 前提是…

原来“山水博客“的分类也是可以拖动排序的

这二天一直用“山水博客”写文章&#xff0c;发现一个问题&#xff0c;好象它的分类不能调整位置&#xff0c;这可是个大bug。首先&#xff0c;界面上没发现拖动相关按钮&#xff1b;如果按住分类拖动&#xff0c;会成这样&#xff1a; 后来仔细看了它的文档&#xff0c;发现它…

智能社区服务小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;房屋信息管理&#xff0c;住户信息管理&#xff0c;家政服务管理&#xff0c;家政预约管理&#xff0c;报修信息管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;房屋信…

水果品牌网站开展如何拓宽渠道

对大多数人来说&#xff0c;零售买水果只在乎是买什么水果、哪个产地、价格等因此&#xff0c;对品牌的依赖度相对较低。但对于水果品牌公司来说&#xff0c;货好仅是基本&#xff0c;还需要将品牌发展出去、能获取准属性客户和转化路径。 与零售不同&#xff0c;批发生意或是…

在vs上远程连接Linux写服务器项目并启动后,可以看到服务启动了,但是通过浏览器访问该服务提示找不到页面

应该是被防火墙挡住了&#xff0c;查看这个如何检查linux服务器被防火墙挡住 • Worktile社区 和这个关于Linux下Nginx服务启动&#xff0c;通过浏览器无法访问的问题_linux无法访问nginx-CSDN博客 的提示之后&#xff0c;知道防火墙开了&#xff0c;想着可能是我写的服务器的…

大数据面试题之Spark(1)

目录 Spark的任务执行流程 Spark的运行流程 Spark的作业运行流程是怎么样的? Spark的特点 Spark源码中的任务调度 Spark作业调度 Spark的架构 Spark的使用场景 Spark on standalone模型、YARN架构模型(画架构图) Spark的yarn-cluster涉及的参数有哪些? Spark提交jo…

c++类成员指针用法

1&#xff09;C入门级小知识&#xff0c;分享给将要学习或者正在学习C开发的同学。 2&#xff09;内容属于原创&#xff0c;若转载&#xff0c;请说明出处。 3&#xff09;提供相关问题有偿答疑和支持。 c中新增类成员指针操作&#xff0c;为了访问方便&#xff0c;他是指…

Spring Boot项目如何配置跨域

1、通过SpringSecurity进行配置 2、前端跨域配置&#xff1a;proxy配置项用于设置代理规则&#xff0c;用于前端开发中与后端API交互时使用。

《HelloGitHub》第 99 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

JS乌龟吃鸡游戏

代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>乌龟游戏</title><script type"text/javascript">function move(obj){//乌龟图片高度var wuGui_height 67;…

pikachu靶场 利用Rce上传一句话木马案例(工具:中国蚁剑)

目录 一、准备靶场&#xff0c;进入RCE 二、测试写入文件 三、使用中国蚁剑 一、准备靶场&#xff0c;进入RCE 我这里用的是pikachu 打开pikachu靶场&#xff0c;选择 RCE > exec "ping" 测试是否存在 Rce 漏洞 因为我们猜测在这个 ping 功能是直接调用系统…

这四款软件很好用,可以提升工作、学习效率

TableConvert TableConvert是一个基于Web的在线表格转换工具&#xff0c;能够将多种格式的表格数据进行快速转换。它支持将Excel、URL、HTML、JSON、CSV等格式转换为Markdown表、CSV/TSV、XML、YAML、插入SQL、HTML、Excel和LaTeX等格式。用户只需将表格数据粘贴到编辑器&#…

[C++][设计模式][适配器模式]详细讲解

目录 1.动机2.模式定义3.要点总结4.代码感受 1.动机 在软件系统中&#xff0c;由于应用环境的变化&#xff0c;常常需要将”一些现存的对象“放在新的环境中应用&#xff0c;但是新环境要求的接口是这些现存对象所不满足如何应对这些”迁移的变化“&#xff1f;如何既能利用现…