微服务项目->在线oj系统(Java版 - 4)

news2025/5/24 7:54:53

相信自己,终会成功

目录

B端用户管理

C端用户代码

发送验证码:

验证验证码

退出登录

登录用户信息功能

 用户详情与用户编辑

 用户竞赛接口

用户报名竞赛

用户竞赛报名接口查询

 用户信息列表

ThreadLocalUtil

Hutool工具库

常用功能介绍 


B端用户管理

进行列表显示与用户状态修改(拉黑操作)

用户列表显示主要运用了分页管理给前端传输数据(UserVO)从而在页面上显示

拉黑操作,根据前端传送过来的数据,在数据库中根据用户id搜索此用户,失败返回异常

成功执行user.setStatus(userDTO.getStatus()); 作用是把 userDTO 里的状态值赋给 user 对象

userCacheManager.updateStatus(user.getUserId(), userDTO.getStatus()); 则是让缓存中的用户状态与新状态保持一致,执行 updateStatus 函数,先刷新用户缓存,

@Override
    public List<UserVO> list(UserQueryDTO userQueryDTO) {
        PageHelper.startPage(userQueryDTO.getPageNum(),userQueryDTO.getPageSize());
        return userMapper.selectUserList(userQueryDTO);
    }

    @Override
    public int updateStatus(UserDTO userDTO) {
        User user = userMapper.selectById(userDTO.getUserId());
        if(user==null){
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        //这里是从前端拿到的值,假设前端把用户拉黑,返回的就是0,设置也就是0
        user.setStatus(userDTO.getStatus());
        userCacheManager.updateStatus(user.getUserId(),userDTO.getStatus());
        return userMapper.updateById(user);
    }

    public void updateStatus(Long userId,Integer status) {
        //刷新用户缓存
        String userKey = getUserKey(userId);
        User user = redisService.getCacheObject(userKey, User.class);
        if(user==null){
            return;
        }
        user.setStatus(status);
        redisService.setCacheObject(userKey, user);
        //设置用户缓存有效期为10分钟
        redisService.expire(userKey, CacheConstants.USER_EXP, TimeUnit.MINUTES);
    }

getCacheObiect中从Redis缓存中获取对象并转换为指定类型 

从redis缓存中获取指定key的对象,并将其转换为指定类型的示例

 /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key, Class<T> clazz) {
  
 // 获取 Redis 的 Value 操作对象
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
  
// 从缓存中获取对象
        T t = operation.get(key); 
  
// 如果缓存值是 String 类型且目标类型也是 String,则直接返回
        if (t instanceof String) {
            return t;
        }
    
// 否则尝试将对象转换为 JSON 字符串并解析为目标类型
        return JSON.parseObject(String.valueOf(t), clazz);
    }

C端用户代码

发送验证码:

从前端拿到数据,获取到用户手机号码,

进入validatePhone(phone);用于判断phone是否为空(StrUtil.isBlank(phone),isStrUtil.isBlank是Hutool工具类下的方法Hutool工具类下方有介绍),为空执行异常,不为空判断手机号格式是否正确,如果正确,则正常进行频率检查

checkDailyRequestLimit()检查每日请求限制

成Redis存储的key(格式示例:c:t:13800138000),从redis获取已发送次数(String类型),转化发送次数为Long类型(若为空则默认为0),给sendTimes赋值,与每日限制次数(sendLimit)进行对比,结果为true则抛出异常

@Override
    public boolean sendCode(UserDTO userDTO) {
        // 1. 参数校验
        String phone = userDTO.getPhone();
        validatePhone(phone);

        // 2. 频率控制检查
        checkRequestFrequency(phone);

        // 3. 每日限额检查
        checkDailyRequestLimit(phone);

        // 4. 生成并存储验证码
        String code = generateVerificationCode(phone);

        // 5. 发送验证码
        sendVerificationCode(phone, code);

        System.out.println("code: "+code);
        return true;

    }
    private void validatePhone(String phone) {
        if (StrUtil.isBlank(phone)) {
            throw new ServiceException(ResultCode.FAILED_USER_PHONE_EMPTY);
        }

        // 中国手机号正则(11位,1开头)
        String regex = "^1[3-9]\\d{9}$";
        if (!Pattern.matches(regex, phone)) {
            throw new ServiceException(ResultCode.FAILED_USER_PHONE_INVALID);
        }
    }

  private void checkRequestFrequency(String phone) {
        // getExpire()获取当前 Key 的剩余生存时间
        String phoneCodeKey = getPhoneCodeKey(phone);
        Long expire = redisService.getExpire(phoneCodeKey, TimeUnit.SECONDS);
        // 如果上一次验证码的发送时间距离现在 不足1分钟(即 总有效期 - 剩余时间 < 60秒),则拒绝新请求。
        if (expire != null && (emailCodeExpiration * 60 - expire) < 60) {
            throw new ServiceException(ResultCode.FAILED_FREQUENT);
        }
    }


 private void checkDailyRequestLimit(String phone) {
        // 每天的验证码获取次数有一个限制  50 次 , 第二天  计数清0 重新开始计数
        // 计数  怎么存,存在哪里 ?
        // 操作次数数据频繁,不需要存储,  记录的次数  有效时间(当天有效) redis String  key: c:t:
        // 1.获取已经请求的次数 和 50 进行比较
        String codeTimeKey = getCodeTimeKey(phone);
        String sendTimesStr = redisService.getCacheObject(codeTimeKey, String.class);
        Long sendTimes = sendTimesStr != null ? Long.parseLong(sendTimesStr) : 0L;
        // 如果大于限制,抛出异常
        // 如果不大于限制,正常执行后续逻辑,并且将获取计数+1
        if (sendTimes >= sendLimit) {
            throw new ServiceException(ResultCode.FAILED_TIME_LIMIT);
        }
    }

验证验证码

对比验证码是否正确,如果正确,根据输入的phone去数据库中查询

如果user为null则在数据库中添加一个新用户,添加手机号,用户状态

最后生成专属令牌,用于后续验证

   @Override
    public String codeLogin(String phone, String code) {
        //判断验证码是否正确
        CheckCode(phone,code);
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
        if(user==null){   //新用户
            //注册逻辑 1.先完成验证码的比对->成功,往系统中增加用户
            user=new User();
            user.setPhone(phone);
            user.setStatus(UserStatus.Normal.getValue());
            userMapper.insert(user);
        }
        return tokenService.createToken(user.getUserId(),secret, UserIdentity.ORDINARY.getValue(),user.getNickName(),user.getHeadImage());

private void CheckCode(String phone, String code) {
        String phoneCodeKey = getPhoneCodeKey(phone);
        String cacheCode = redisService.getCacheObject(phoneCodeKey,String.class);

        if(StrUtil.isEmpty(cacheCode)){
            throw new ServiceException(ResultCode.FAILED_INVALID_CODE);
        }
        if(!cacheCode.equals(code)){
            throw new ServiceException(ResultCode.FAILED_CODE_MISMATCH);
        }
        redisService.deleteObject(phoneCodeKey);
    }

退出登录

最开始检测token是否为空这步是一个保障,防止没有生成令牌

public static final String PREFIX = "Bearer ";为令牌前缀,如果存在令牌前缀则把前缀替换成空

最后删除令牌

 @Override
    public boolean logout(String token) {
        //检查token是否为空
        if (StrUtil.isEmpty(token)) {
            throw new ServiceException(ResultCode.TOKEN_IS_DEFAULT);
        }
        //再处理前缀
        if (token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX,StrUtil.EMPTY);
        }

        return tokenService.deleteLoginUser(token,secret);

    }

登录用户信息功能

LoginUserVO,返回给前端的数据(包括头像和昵称)

根据token获取登录用户信息返回,包含用户基本信息的VO对象

用户头像字段需要拼接下载地址前缀,使用StrUtil.isNotEmpty确保头像字段非空


    @Override
    public R<LoginUserVO> info(String token) {

//        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
//            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
//        }

        // 先检查token是否为空
        if (StrUtil.isEmpty(token)) {
            throw new ServiceException(ResultCode.TOKEN_IS_DEFAULT);
        }
//      再处理前缀
        if (token.startsWith(HttpConstants.PREFIX)) {
            token = token.substring(HttpConstants.PREFIX.length());
        }

        LoginUser loginUser = tokenService.getLoginUser(token, secret);

        if(loginUser==null){
            return R.fail();
        }
        LoginUserVO loginUserVO=new LoginUserVO();
        loginUserVO.setNickName(loginUser.getNickName());
        if(StrUtil.isNotEmpty(loginUser.getHeadImage())){
            loginUserVO.setHeadImage(download+loginUser.getHeadImage());
        }
        return R.ok(loginUserVO);
    }

 用户详情与用户编辑

用户详情

从线程池中获取userId的值

定义一个userVO对象,从数据库中根据userId查询内容赋值给userVO

如果用户存在,设置头像,存入userVO,最后返回给前端

用户编辑

先把用户获取出来,根据前端输入的内容去跟新数据库中的值

最后更新缓存

extracted(),刷新用户缓存和登录状态信息

UserCacheManager .refreshUser: 用户缓存刷新接口

TokenService.refreshLoginUser: Token信息刷新接口

 @Override
    public UserVO detail() {
        Long userId= ThreadLocalUtil.get(Constants.USER_ID,Long.class);
        if(userId==null){
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        UserVO userVO;
        userVO=userCacheManager.getUserById(userId);
        if(userVO==null){
            throw new ServiceException(ResultCode.FAILED_USER_NOT_EXISTS);
        }
        if(StrUtil.isNotEmpty(userVO.getHeadImage())){
            userVO.setHeadImage(download+userVO.getHeadImage());
        }
        return userVO;
    }
 @Override
    public int edit(UserUpdateDTO userUpdateDTO) {
        User user = getUser();
        user.setNickName(userUpdateDTO.getNickName());
        user.setSex(userUpdateDTO.getSex());
        user.setSchoolName(userUpdateDTO.getSchoolName());
        user.setMajorName(userUpdateDTO.getMajorName());
        user.setPhone(userUpdateDTO.getPhone());
        user.setEmail(userUpdateDTO.getEmail());
        user.setWechat(userUpdateDTO.getWechat());
        user.setIntroduce(userUpdateDTO.getIntroduce());
        //更新用户缓存
        extracted(user);
        return userMapper.updateById(user);
    }

    private void extracted(User user) {
        userCacheManager.refreshUser(user);
        tokenService.refreshLoginUser(user.getNickName(), user.getHeadImage(),
                ThreadLocalUtil.get(Constants.USER_KEY, String.class));
    }

 用户竞赛接口

用户报名竞赛

获取当前用户信息,筛选用户是否符合条件(1.用户处于登录状态 2.不能报名不存在的竞赛 3.不能重复报名 4.已经开赛的禁止报名)

条件符合之后,往用户竞赛表中添加数据(底层使用list结构存储数据(头插法))

  @Override
    public int enter(String token, Long examId) {

//        获取当前用户的信息  status
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
//        UserVO user = userCacheManager.getUserById(userId);
//        if (user.getStatus()==0){
//            throw new ServiceException(ResultCode.FAILED_USER_BANNED);
//        }

        //使用spring aop

//报名是否符合条件 (1.用户处于登录状态 2.不能报名不存在的竞赛 3.不能重复报名 4.已经开赛的禁止报名)
        Exam exam = examMapper.selectById(examId);
        if(exam==null){
            throw new ServiceException(ResultCode.EXAM_RESULT_NOT_EXIST);
        }
        if(exam.getStartTime().isBefore(LocalDateTime.now())){
            throw new ServiceException(ResultCode.EXAM_IS_START);
        }
//        Long userId= tokenService.getUserId(token,secret);
//        Long userId = userId;
        UserExam userExam = userExamMapper.selectOne(new LambdaQueryWrapper<UserExam>()
                .eq(UserExam::getExamId, examId)
                .eq(UserExam::getUserId, userId));
        if(userExam!=null){
            throw new ServiceException(ResultCode.USER_EXAM_HAS_ENTER);
        }
        examCacheManager.addUserExamCache(userId, examId);
        userExam=new UserExam();
        userExam.setExamId(examId);
        userExam.setUserId(userId);
        return userExamMapper.insert(userExam);
    }

用户竞赛报名接口查询

type :0:代表未完赛 1:代表历史竞赛 

先查询用户信息,把type的值设置为2,

userExamMapper.selectUserExamList(userId)根据userId获取指定类型的考试列表长度

判断type和userId是否为空

不为空生成redis唯一标识符,返回一个json形式的数据

  @Override
    public TableDataInfo list(ExamQueryDTO examQueryDTO) {
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        examQueryDTO.setType(ExamListType.USER_EXAM_LIST.getValue());
        Long total = examCacheManager.getListSize(ExamListType.USER_EXAM_LIST.getValue(),userId);
        List<ExamVO> examVOList;
        if(total == null || total <= 0){//缓存不存在时的处理:
            //从数据库中查询我的竞赛列表
            PageHelper.startPage(examQueryDTO.getPageNum(),examQueryDTO.getPageSize());
            examVOList = userExamMapper.selectUserExamList(userId);
            //将数据库中的数据同步给缓存
            examCacheManager.refreshCache(examQueryDTO.getType(),userId);
            //从数据库中查询
            total=new PageInfo<>(examVOList).getTotal();
        }else{//缓存存在时的处理:
            examVOList = examCacheManager.getExamVOList(examQueryDTO,userId);
            //从redis中查询,在查询时,出现异常情况,可能会重新刷新数据,这次查询用户数据的更新
//            0:代表未完赛 1:表示开始竞赛
            total = examCacheManager.getListSize(examQueryDTO.getType(),userId);
        }
//        空结果处理:
        if  (CollectionUtil.isEmpty(examVOList)){
            return TableDataInfo.empty();
        }
        //获取符合查询条件的数据总数
        //从数据库中查询数据,不是从redis中查询数据
        return TableDataInfo.success(examVOList,total);

    }
public Long getListSize(Integer examListType, Long userId) {
    // 1. 参数校验(示例,根据实际需求调整)
    if (examListType == null || userId == null) {
        throw new IllegalArgumentException("参数不能为null");
    }

    // 2. 生成业务唯一的Redis键
    String examListKey = getExamListKey(examListType, userId);
    
    // 3. 获取Redis列表长度(返回Long类型,可能为0)
    return redisService.getListSize(examListKey);
}
 //未查出任何数据时调用
    public static TableDataInfo empty() {
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(ResultCode.SUCCESS.getCode());
        rspData.setRows(new ArrayList<>());
        rspData.setMsg(ResultCode.SUCCESS.getMsg());
        rspData.setTotal(0);
        return rspData;
    }

    //查出数据时调用
    public static TableDataInfo success(List<?> list,long total) {
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(ResultCode.SUCCESS.getCode());
        rspData.setRows(list);
        rspData.setMsg(ResultCode.SUCCESS.getMsg());
        rspData.setTotal(total);
        return rspData;
    }

 用户信息列表

获取用户消息列表(带分页,优先从缓存读取)

从ThreadLocal获取当前用户ID 检查缓存中是否存在消息列表

缓存不存在,为空时查询数据库并刷新缓存

返回分页格式的统一响应

public TableDataInfo list(PageQueryDTO dto) {
    // 1. 获取当前用户ID(从线程上下文)
    Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
    if (userId == null) {
        throw new ServiceException("用户未登录");
    }

    // 2. 检查缓存是否存在有效数据
    Long total = messageCacheManager.getListSize(userId);
    List<MessageTextVO> messageTextVOList;
    
    // 3. 缓存不存在时走数据库查询
    if (total == null || total <= 0) {
        // 3.1 启用分页查询
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        messageTextVOList = messageTextMapper.selectUserMsgList(userId);
        
        // 3.2 刷新缓存
        messageCacheManager.refreshCache(userId);
        total = new PageInfo<>(messageTextVOList).getTotal();
    } 
    // 4. 缓存存在时直接读取
    else {
        messageTextVOList = messageCacheManager.getMsgTextVOList(dto, userId);
    }

    // 5. 处理空结果
    if (CollectionUtil.isEmpty(messageTextVOList)) {
        return TableDataInfo.empty();
    }
    
    // 6. 返回统一分页响应
    return TableDataInfo.success(messageTextVOList, total);
}

ThreadLocalUtil

ThreadLocalUtil是一个工具类,封装了Java的ThreadLocal操作,ThreadLocal工具类(基于TransmittableThreadLocal实现)

封装线程隔离的变量存储功能,解决原生ThreadLocal在线程池场景下的数据污染问题

使用TransmittableThreadLocal替代原生ThreadLocal,支持线程池环境

每个线程独立维护ConcurrentHashMap存储数据,线程安全

自动处理null值存储(转为空字符串)

必须显式调用remove()避免内存泄漏详情看注释


//ThreadLocalUtil是一个工具类,封装了Java的ThreadLocal操作,
//用于实现线程隔离的变量存储(每个线程独立存取数据,互不干扰)。
public class ThreadLocalUtil {
//    使用 TransmittableThreadLocal(而非原生 ThreadLocal),
//    解决原生 ThreadLocal 在线程池中线程复用导致的数据错乱问题。
    private static final TransmittableThreadLocal<Map<String, Object>>
            THREAD_LOCAL = new TransmittableThreadLocal<>();

    /**
     * 存储键值对到当前线程上下文
     * @param key 键(非空)
     * @param value 值(自动转换null为空字符串)
     */

    public static void set(String key, Object value) {
        Map<String, Object> map = getLocalMap();
        map.put(key, value == null ? StrUtil.EMPTY : value);
    }

    /**
     * 从当前线程上下文获取值(带类型转换)
     * @param key 键
     * @param clazz 目标类型Class对象
     * @return 值(不存在时返回null)
     * @param <T> 返回值泛型
     */
    public static <T> T get(String key, Class<T> clazz) {
        Map<String, Object> map = getLocalMap();
        return (T) map.getOrDefault(key, null);
    }

    /**
     * 获取当前线程的存储Map(不存在时自动初始化)
     * 
     * 注意:使用ConcurrentHashMap保证线程安全</p>
     * 
     * @return 当前线程关联的Map(永不为null)
     */

//    每个线程独立维护一个 Map<String, Object>,
//    通过键值对(Key-Value)存储数据,线程间数据互不干扰。
    public static Map<String, Object> getLocalMap() {
        Map<String, Object> map = THREAD_LOCAL.get();
        if (map == null) {
            map = new ConcurrentHashMap<String, Object>();
            THREAD_LOCAL.set(map);
        }
        return map;
    }

     /**
     * 清除当前线程的存储Map(
     * 
     *   使用场景:
     *   线程池场景必须调用,避免内存泄漏
     *   请求处理结束时建议调用
     */

    //清除当前线程的 Map,防止内存泄漏(尤其在线程池场景中必须调用)
    public static void remove() {
        THREAD_LOCAL.remove();
    }
}

 

Hutool工具库

官方网站:

Hutool🍬一个功能丰富且易用的Java工具库,涵盖了字符串、数字、集合、编码、日期、文件、IO、加密、数据库JDBC、JSON、HTTP客户端等功能。

导入依赖

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-core</artifactId>
    <version>5.8.16</version> <!-- 以最新版本为准 -->
</dependency>

常用功能介绍 

1.1 字符串工具(StrUtil)

import cn.hutool.core.util.StrUtil;

// 判空
boolean isBlank = StrUtil.isBlank("  "); // true(空或空白字符)
boolean isEmpty = StrUtil.isEmpty("");   // true(仅空字符串)

// 格式化字符串
String formatted = StrUtil.format("Hello, {}!", "Hutool"); // "Hello, Hutool!"

// 字符串截取、填充、反转
String sub = StrUtil.sub("HelloWorld", 2, 5); // "llo"
String padded = StrUtil.padPre("123", 5, '0'); // "00123"
String reversed = StrUtil.reverse("ABC"); // "CBA"

1.2 数字工具(NumberUtil)

import cn.hutool.core.util.NumberUtil;

// 数学计算
int sum = NumberUtil.add(1, 2, 3); // 6
double div = NumberUtil.div(10, 3, 2); // 3.33(保留2位小数)

// 数字判断
boolean isNumber = NumberUtil.isNumber("123.45"); // true
boolean isInteger = NumberUtil.isInteger("100"); // true

1.3 日期时间工具(DateUtil)

import cn.hutool.core.date.DateUtil;

// 日期解析与格式化
Date date = DateUtil.parse("2023-10-01"); // String → Date
String dateStr = DateUtil.format(date, "yyyy/MM/dd"); // "2023/10/01"

// 日期计算
Date tomorrow = DateUtil.offsetDay(new Date(), 1); // 明天
long betweenDays = DateUtil.between(date, new Date(), DateUnit.DAY); // 相差天数

// 获取时间部分
int year = DateUtil.year(date); // 2023
int month = DateUtil.month(date) + 1; // 10(月份从0开始)

1.4 集合工具(CollUtil)

import cn.hutool.core.collection.CollUtil;

List<String> list = CollUtil.newArrayList("A", "B", "C");

// 判空
boolean isEmpty = CollUtil.isEmpty(list); // false

// 集合操作
List<String> reversedList = CollUtil.reverse(list); // ["C", "B", "A"]
String joined = CollUtil.join(list, ","); // "A,B,C"

2.1 文件工具(FileUtil)

import cn.hutool.core.io.FileUtil;

// 读取文件内容
String content = FileUtil.readUtf8String("test.txt");

// 写入文件
FileUtil.writeUtf8String("Hello, Hutool!", "output.txt");

// 文件操作
boolean exists = FileUtil.exist("test.txt"); // 检查文件是否存在
FileUtil.copy("src.txt", "dest.txt", true); // 复制文件(覆盖)
FileUtil.del("temp_dir"); // 删除目录

2.2 流工具(IoUtil)

import cn.hutool.core.io.IoUtil;

// 流拷贝(自动关闭流)
try (InputStream in = new FileInputStream("src.txt");
     OutputStream out = new FileOutputStream("dest.txt")) {
    IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE);
}

3.1 摘要加密(DigestUtil)

import cn.hutool.crypto.digest.DigestUtil;

// MD5
String md5 = DigestUtil.md5Hex("123456"); // "e10adc3949ba59abbe56e057f20f883e"

// SHA-256
String sha256 = DigestUtil.sha256Hex("123456");

// 加盐加密(BCrypt)
String hashed = BCrypt.hashpw("password");
boolean isMatch = BCrypt.checkpw("password", hashed); // 校验

 3.2 对称加密(AES、DES)

import cn.hutool.crypto.SecureUtil;

// AES 加密
String key = "1234567890abcdef"; // 16/24/32位密钥
String encrypted = SecureUtil.aes(key.getBytes()).encryptHex("Hello");
String decrypted = SecureUtil.aes(key.getBytes()).decryptStr(encrypted);
模块主要功能常用类
hutool-core字符串、日期、集合、数字StrUtilDateUtilCollUtil
hutool-httpHTTP 请求HttpUtil
hutool-crypto加密解密(MD5、AES、BCrypt)DigestUtilSecureUtil
hutool-jsonJSON/XML 处理JSONUtilXmlUtil
hutool-extra文件、IO、邮件等FileUtilMailUtil

 

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

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

相关文章

ReAct 与 CoAct:AI 代理的推理与行动之旅

引言 能推理又能行动的 AI 代理&#xff0c;是朝着构建更自主系统迈出的重要一步。传统上&#xff0c;语言模型在“思维链”提示方面表现得很出色&#xff0c;也就是通过文本逐步思考问题来解决像算术、常识问题或符号推理这类任务。但用思维链时&#xff0c;模型只依赖自身的…

uni-app使用大集

1、手动修改页面标题 uni.setNavigationBarTitle({title: 修改标题 }); 2、单选 不止有 radio-group&#xff0c;还有 uni-data-checkbox 数据选择器 <!-- html部分 --> <uni-data-checkbox v-model"sex" :localdata"checkboxList"></u…

零件剖切配置教学 | 玩转EasyTwin 工业产线第三期(上)课程回顾

-在工业数字孪生领域&#xff0c;工程施工模拟、车间产线运转、机械装置和零件配置等交互效果的呈现至关重要。通过EasyTwin&#xff0c;我们能够以更低成本、更高效率来构建数字孪生场景&#xff0c;但在搭建的过程中&#xff0c;也会因为复杂的场景交互配置产生一些疑问。该案…

onnx模型转入rknn3399平台上工作记录

1.rknn虚拟环境使用时报错问题 使用rknn17环境的报错&#xff1a; ImportError: libdc1394.so.22: cannot open shared object file: No such file or directory 参考链接&#xff1a;https://blog.csdn.net/2301_80032564/article/details/142316410 创作软连接&#xff1a; …

第三个小程序动工:一款结合ai的菜谱小程序

1.环境搭建&#xff0c;与初步运行 安装及使用 | Taro 文档 找到一个合适的文件夹&#xff0c;cmd D:\gitee>pnpm install -g tarojs/cli╭──────────────────────────────────────────╮│ …

OpenCV CUDA 模块图像过滤------创建一个线性滤波器(Linear Filter)函数createLinearFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数用于创建一个线性滤波器&#xff08;Linear Filter&#xff09;&#xff0c;可以对图像执行任意用户定义的卷积核&#xff08;kernel&…

Excel 密码忘记了?巧用PassFab for Excel 解密帮您找回数据!

在工作中&#xff0c;你是否遇到过这样的尴尬时刻&#xff1f;打开重要的 Excel 文件&#xff0c;却发现忘记密码&#xff0c;里面的财务报表、客户数据、项目计划瞬间变成 “加密天书”。重新制作耗时耗力&#xff0c;找专业人员解密又担心数据泄露&#xff0c;这个时候&#…

Vue.js教学第十二章:Vue Router实战指南(二)

Vue Router(二):深入剖析 Vue Router 高级特性 在前端开发领域,Vue.js 框架凭借其简洁、灵活和高效的特点,得到了广泛应用。而 Vue Router 作为 Vue.js 的官方路由管理器,为构建单页面应用(SPA)提供了强大的支持。本文将深入探究 Vue Router 的高级特性,包括路由的动…

【前端开发】Uniapp日期时间选择器:实现分钟动态步长设置

技术栈 Uniapp Vue3 uView年份显示前后一年&#xff0c;分钟动态设置间隔 效果图 主体显示 <view class"uni-row-between selector"><view class"uni-flex-1 left" click"!props.disabled && openPicker()"><uni-icons…

Visual Studio已更新为17.14+集成deepseek实现高效编程

01 Visual Studio 2022 v17.14。 此更新侧重于全面提供出色的开发人员体验&#xff0c;侧重于稳定性和安全性以及 AI 改进。 02 GPT-4o代码完成模式 我们非常高兴地宣布&#xff0c;新的 GPT-4o Copilot 代码完成模型现已在 Visual Studio 17.14 中为 GitHub Copilot 用户…

养生指南:五维打造健康新方式

一、饮食&#xff1a;天然搭配&#xff0c;科学进食 遵循 “食物多样化” 原则&#xff0c;早餐以红薯玉米粥搭配水煮蛋、凉拌黄瓜&#xff0c;开启活力一天&#xff1b;午餐选用糙米饭、番茄炖牛腩、蒜蓉空心菜&#xff0c;营养均衡&#xff1b;晚餐用冬瓜虾皮汤配上蒸芋头&a…

网络爬虫学习之httpx的使用

开篇 本文整理自《Python3 网络爬虫实战》&#xff0c;主要是httpx的使用。 笔记整理 使用urllib库requests库的使用&#xff0c;已经可以爬取绝大多数网站的数据&#xff0c;但对于某些网站依然无能为力。 这是因为这些网站强制使用HTTP/2.0协议访问&#xff0c;这时urllib和r…

无人机桥梁检测效率问题-高精度3D建模及航线规划

无人机桥梁检测效率问题-高精度3D建模及航线规划 无人机桥梁检测的效率分析 结论-并没有提升效率 飞行任务制定步骤繁琐且续航限制 需要首先对大桥建立高精度的3D建模&#xff0c;根据任务制定无人机的飞行路径以及动作&#xff0c;商用无人机续航通常仅30-40分钟&#xff0c…

想免费使用 AWS 云服务器?注册、验证及开通全攻略

拥有一台 AWS 免费云服务器&#xff0c;可以轻松搭建个人网站、博客或部署 ChatGPT 等 AI 服务。本文详解如何 注册 AWS 账号、完成 信用卡验证&#xff0c;并在 AWS 控制台中 开通 EC2 实例&#xff0c;享受长达 12 个月的免费额度。 提示&#xff1a; 国内信用卡及银联借记卡…

Pandas:数据分析中的缺失值检测、加载、设置、可视化与处理

本文目录&#xff1a; 一、检测数据集中的缺失值&#xff08;一&#xff09;缺失值的判断规则&#xff1a;&#xff08;二&#xff09;代码如下&#xff1a; 二、缺失值加载处理&缺失值设置&#xff08;一&#xff09;缺失值加载处理&#xff08;二&#xff09;缺失值设置 …

【Linux系列】EVS 与 VBD 的对比

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

56 在standby待机打通uart调试的方法

修改点如下&#xff1a; 一&#xff0c;进入standby保证uart通 1, 去掉串口进入休眠RT_DEVICE_CTRL_SUSPEND:关闭uart&#xff0c;保证BSP_IO_Power_Down函数执行完前&#xff0c;串口都可以打印&#xff0c;和通过SifliUsartServer工具串口连接&#xff0c;并debug死机问题&…

OceanBase 共享存储:云原生数据库的存储

目录 探会——第三届 OceanBase 开发者大会 重磅发布&#xff1a;OceanBase 4.3 开发者生态全面升级 实战演讲&#xff1a;用户案例与行业落地 OceanBase 共享存储架构解析 什么是共享存储架构&#xff1f; 云原生数据库的架构 性能、弹性与多云的统一 为何OceanBase能…

安卓新建项目时,Gradle下载慢下载如何用国内的镜像

方法 1&#xff1a;修改 gradle-wrapper.properties 使用国内镜像 Gradle 的下载地址可以在 gradle-wrapper.properties 中修改&#xff0c;替换为国内镜像地址&#xff08;如阿里云、腾讯云等&#xff09;。 步骤 打开项目中的 gradle-wrapper.properties 文件&#xff08;路…

讯联文库开发日志(五)登录拦截校验

零 在此之前&#xff0c;由于主播一直缺乏session&#xff0c;这次两个小时的寻找bug之旅也让我受益颇多 罪魁祸首&#xff1a;key值写错了&#xff0c;导致一直报错&#xff0c;不过这也让我了解了更多关于session的k-v结构 参数校验 我们需要在全局拦截器注解里面加两个方…