苍穹外卖技术栈

news2024/12/28 5:56:10

重难点详解

1、定义全局异常

在这里插入图片描述

2、ThreadLocal

  • ThreadLocal 并不是一个Thread,而是Thread的一个局部变量
  • ThreadLocal 为每一个线程提供独立的存储空间,具有线程隔离的效果,只有在线程内才能取到值,线程外则不能访问
public void set(T value) 设置当前线程的线程局部变量的值

public T get() 返回当前线程所对应的线程局部变量的值

public void remove() 移除当前线程的线程局部变量

注意:客户端每次发送http请求,对应的服务端都会分配一个新的线程,在处理过程中涉及到系列方法属于同一个线程:
【1】LoginCheckFilter的doFilter方法
【2】EmployeeController的update方法
【3】MyMetaObjectHandler的updateFill方法

3、BaseContext上下文

BaseContext是基于ThreadLocal类封装的工具类,用于在同一线程中的封装数据和获取数据

> BaseContext工具类用于存放和取出当前登录的用户的id
> 
public class BaseContext {

    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    /**
     * 设置当前线程的线程局部变量的值
     * @param id
     */
    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }

    public static void removeCurrentId() {
        threadLocal.remove();
    }

4、PageHelper分页

pagehelper是mybatis 提供的分页插件

开始分页

PageHelper.startPage(1, 10)

// selectlist查询数据库的时候会自动加上limit 1,10。

在CategoryServiceImpl声明pageQuery方法,及其父类接口:

    public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {
        // 分页器对象
        Page<Category> page = new Page<>();
        List<Category> categoryList  = categoryMapper.pageQuery(categoryPageQueryDTO);
        Long total = page.getTotal();
        // 分页
        return new PageResult(total,categoryList);
    }
    

在EmployeeServiceImpl声明pageQuery方法,及其父类接口


    public PageResult pageQuery(EmployeePageQueryDTO dto) {

        PageHelper.startPage(dto.getPage(),dto.getPageSize());
        Page<Employee> page = employeeMapper.pageQuery(dto);
        return new PageResult(page.getTotal(),page.getResult());
    }

原理:

  • Mybatis内置了分页拦截器PageInterceptor,即在执行相关sql之前会拦截一些操作
  • 通过`setLocalPage()方法,将分页信息保存在当前线程中。分页查询方法与之处在同一个线程中,共享ThreadLocal中的数据
  • selectlist查询之后赋值给的List list。这个list是Page 类型
  • 再将list放到PageInfo<>中即可。

查询

List<Employee> list = employeeMapper.selectByExample(Example);  

分页结果展示

 PageInfo<Employee> pageInfo = new PageInfo<>(list);  
           System.out.println("总记录数:"+pageInfo.getTotal());  
           System.out.println("总页数:"+pageInfo.getPages());  
           System.out.println("一页的大小:"+pageInfo.getSize());  


5、日期按年月日显示

  • WebMvcConfiguration 中扩展Spring MVC的消息转换器,统一对日期类型进行格式化处理
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("Spring MVC扩展消息转化器...");
        // 创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        // 设置该消息转换器使用 JacksonObjectMapper 进行转换
        messageConverter.setObjectMapper(new JacksonObjectMapper());

        // 将消息转换器对象追加到 mvc 框架的转换器集合中(加到最前面)
        converters.add(0,messageConverter);
    }

在这里插入图片描述

6、启用/禁用账号

/**
* 启用禁用员工账号
*/
@Override
public void startOrStop(Integer status, Long id) {

    Employee employee = Employee.builder()
            .status(status)
            .id(id)
            .build();

    employeeMapper.update(employee);
}

Employee.builder().build()建造者模式,builder构造对象;@Builder 注解

6、公共字段填充

mybatis-plus提供了公共字段自动填充功能

// 在EmployeeMapper
@AutoFill(value = OperationType.INSERT)
void insert(Employee employee);

@AutoFill(value = OperationType.UPDATE)
void update(Employee employee);

// CategoryMapper
@AutoFill(value = OperationType.INSERT)
void insert(Category category);

@AutoFill(value = OperationType.UPDATE)
void update(Category category);

实现步骤
【1】实体类的属性上加入注解@TableField

create_time,create_user 使用 Insert
update_time,update_user 使用 Insert/update
FieldFill.DEFAULT  //默认不自动填充

    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

【2】元数据对象处理器,实现MetaObjectHandler接口,

@Slf4j
@Component // 交给spring管理
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill...");
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("createUser", BaseContext.getCurrentId());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());
    }


    @Override
    public void updateFill(MetaObject metaObject) {

        log.info("start update fill...");

        long id = Thread.currentThread().getId();

        log.info("当前线程id:{}",id);
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());

    }

7、文件上传

 @PostMapping("/upload")
    @ApiOperation("文件上传")
    public Result<String> upload(MultipartFile file){
        log.info("文件上传: {}", file);

        try {
            // 原始文件名
            String originalFilename = file.getOriginalFilename();
            // 截取原始文件名的后缀
            String suffix= originalFilename.substring(originalFilename.lastIndexOf("."));
            // 构造新文件名称
            String objectName = UUID.randomUUID().toString() + extension;
// 文件的请求路径
		File dir = new File(basePath);// 创建一个目录对象
		//	将临时文件转存到指定位置
file.transferTo(new File(basePath+fileName));

7、请求参数requestparam与requestbody

@ResquestBody要搭配@PostMapping使用,@ResquestParam要搭配@GetMapping使用
区别equestparam与requestbody

  • 【@RequestParam】接收的参数是来自HTTP请求体或请求url的QueryString中
public void aliReceive(@RequestParam("message") String message)

@RequestParam用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容

@RequestParam 接受JSON的字符串

@RequestParam注解无法读取application/json格式数据

  • 【@RequestBody】一般用来处理application/json、application/xml等类型的数据。

POST请求中,通过HttpEntity传递的参数,必须要在请求头中声明数据的类型Content-Type,SpringMVC通过使用

  • 【@PathVariable】
// 参数名和url变量名不一致
@RequestMapping("/user/{id}")
public String testPathVariable(@PathVariable("id") String userId){
    System.out.println("路径上的占位符的值="+id);
}

// 参数名和url变量名一致
@RequestMapping("/getUser/{name}")
    public User getUser(@PathVariable String name){
        return userService.selectUser(name);
    }
    
通过@PathVariable,例如/blogs/1
通过@RequestParam,例如blogs?blogId=1

8、HttpClient

【发送请求步骤】

  • 创建HttpClient对象
  • 创建请求对象HttpGet、HttpPost等
  • 请求对象调用HttpClient的execute方法发送请求
/**
 * 测试通过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();
}

9、微信小程序登录

在application-dev.yml中写入具体的配置属性

sky
  wechat:
    appid: ${sky.wechat.appid}
    secret: ${sky.wechat.secret}

创建user/UserController,创建微信登录的方法

@PostMapping("/login")
    @ApiOperation("微信登录")
    public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO){
        log.info("微信用户登录:{}",userLoginDTO);
        // 微信登录
        User user = userService.wxLogin(userLoginDTO);
        
        // 为微信用户生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getId());
        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);

        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .openid(user.getOpenid())
                .token(token)
                .build();

        return Result.success(userLoginVO);

在UserServiceImpl中,实现wxLogin的方法,及其父类接口

 // 微信服务接口地址
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
public User wxLogin(UserLoginDTO userLoginDTO) {

        String openid = getOpenid(userLoginDTO.getCode());

        // 判断openid是否为空,如果为空表示登录失败,抛出业务异常
        if (openid == null){
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }

        // 判断当前用户是否为新用户
        User user = userMapper.getByOpenId(openid);

        // 如果是新用户,自动完成注册
        if (user == null){
            user = User.builder()
                    .openid(openid)
                    .createTime(LocalDateTime.now())
                    .build();
            userMapper.insert(user);
        }

        private String getOpenid(String code){
        // 调用微信接口服务,获取当前微信用户的openid
        Map<String, String> map = new HashMap<>();
        map.put("appid", weChatProperties.getAppid());
        map.put("secret", weChatProperties.getSecret());
        map.put("js_code", code);
        map.put("grant_type", "authorization_code");
        String json = HttpClientUtil.doGet(WX_LOGIN, map);

        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");

        return openid;
    }

编写JwtTokenUserInterceptor拦截器,校验用户端token是否是合法的

public class JwtTokenUserInterceptor implements HandlerInterceptor {...}

在WebMvcConfiguration中,注册拦截器


@Autowired
private JwtTokenUserInterceptor jwtTokenUserInterceptor;

protected void addInterceptors(InterceptorRegistry registry) {
    log.info("开始注册自定义拦截器...");
    registry.addInterceptor(jwtTokenAdminInterceptor)
            .addPathPatterns("/admin/**")
            .excludePathPatterns("/admin/employee/login");

    registry.addInterceptor(jwtTokenUserInterceptor)
            .addPathPatterns("/user/**")
            .excludePathPatterns("/user/user/login")
            .excludePathPatterns("/user/shop/status");

10、Redis缓存

RedisTemplate是Spring Data Redis提供给用户的最高级的抽象客户端,用户可直接通过RedisTemplate进行多种操作、异常处理、序列化、发布订阅等
————————————————————
spring-data-redis的提供了如下功能:

  1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
  2. 进行了归类封装,将同一类型操作封装为operation接口

ValueOperations:简单K-V操作 redisTemplate.opsForValue().
SetOperations:set类型数据操作 redisTemplate.opsForSet().
ZSetOperations:zset类型数据操作 redisTemplate.opsForZSet().
HashOperations:针对map类型的数据操作 redisTemplate.opsForHash()
ListOperations:针对list类型的数据操作 redisTemplate.opsForList().

  1. 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)
  1. JdkSerializationRedisSerializer:POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。
  1. StringRedisSerializer:Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“newString(bytes,charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
  1. JacksonJsonRedisSerializer:jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。
  1. OxmSerializer:提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】

11.BeanUtils

BeanUtils.copyProperties的用法

常见场景:

  • 接口中将前端请求参数xxVo,转化为xxQuery对象,查询数据库条件对象
BeanUtils.copyProperties(source,target);

BeanUtils.copyProperties("要转换的类", "转换后的类");
  1. 源对象source的属性拷贝值赋给目标对象target的过程中,属性名和属性类型都相同的属性才能被成功拷贝赋值
  2. 做赋值的属性一定要有对应的setter/getter才能成功赋值
  3. 1.对于类型为Boolean/Short/Integer/Float/Double的属性,它会转换为0
  4. java.util.Date/BigDecimal/java.sql.Date/java.sql.Timestamp/java.sql.Time这几个类,如果值为null,则在copy时会抛异常,需要使用对应的Conveter:

org.springframework.beans.BeanUtils BeanUtils.copyProperties(a, b):a复制到b
org.apache.commons.beanutils.BeanUtilsBeanUtils.copyProperties(a, b):b复制到a

12、Spring Task定时处理

Spring Task 是Spring框架提供的任务调度工具

【Spring Task实现步骤】

  1. 导入maven左边
  2. 启动类添加@EnableScheduling注解,开启任务调度
  3. 自定义定时任务 @Scheduled(cron=" ")
    @Scheduled(cron = "0 * * * * ? *") // 每分钟触发一次
    public void processTimeoutOrder(){
        log.info("定时处理超时订单:{}", LocalDateTime.now());

13、WebSocket

WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接, 并进行双向数据传输

创建websocket/WebSocketServer,实现WebSocket服务

@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {

// 存放会话对象
private static Map<String, Session> sessionMap = new HashMap();
		
//连接建立成功
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        System.out.println("客户端:" + sid + "建立连接");
        sessionMap.put(sid, session);
    }
//收到客户端消息
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);
    }
// 关闭连接
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        System.out.println("连接断开:" + sid);
        sessionMap.remove(sid);
    }
// 
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

}

创建WebSocketTask中,通过WebSocket向客户端发送消息

    public void sendMessageToClient() {
        webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
    }

14、LambdaQueryWrapper

LambdaQueryWrapper是Mybatis-Plus框架中的一个查询条件构造器

LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getName, "张三") // 等于eq
            .ne(User::getAge, 18) // 不等于ne
            .gt(User::getSalary, 5000) // 大于gt
            .like(User::getEmail, "abc") //模糊查询
            .orderByDesc(User::getCreateTime);// 降序
List<User> userList = userMapper.selectList(queryWrapper);

15、Nginx

  • 反向代理:允许Nginx服务器代表客户端将请求转发给后端的多个应用服务器
    在这里插入图片描述

16、Spring Cache

Spring Cache 是一个框架,实现了基于注解的缓存功能;底层可以切换不同的缓存实现,如:Redis

    @PostMapping
    @ApiOperation(value = "新增套餐")
    @CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")
    public Result save(@RequestBody SetmealDTO setmealDTO){
        setmealService.save(setmealDTO);
    }
    
    // 修改信息
   @CacheEvict(cacheNames = "setmealCache",allEntries = true)
    public Result update(@RequestBody SetmealDTO setmealDTO){
        setmealService.update(setmealDTO);
        return Result.success();
    }

常用注解:

@EnableCaching // 开启缓存注解功能,启动类上

@Cacheable //在方法执行前查询缓存中是否有数据

@CachePut //将方法的返回值加入缓存中

@CacheEvict //删除缓存

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

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

相关文章

linux入门---动静态库的加载

目录标题 为什么会有动态库和静态库静态库的实现动态库的实现动静态库的加载 为什么会有动态库和静态库 我们来模拟一个场景&#xff0c;首先创建两个头文件 根据文件名便可以得知add.h头文件中存放的是加法函数的声明&#xff0c;sub.h头文件中存放的是减法函数的声明&#…

【每日运维】U盘启动盘安装 ESXi 6.7.0 安装卡在 loading /bnxtroce.v00

问题描述 ● ESXi 6.7.0 安装进度卡在loading /bnxtroce.v00 进度处 处理方法 ● 重新制作启动盘&#xff0c;写入方式改为&#xff1a;【USB-ZIPv2】 ● 设置服务器的 bios设置&#xff0c;启动方式改为【UEFI】 ● 重启开机安装即可

蛋白与蛋白互作预测 蛋白互作预测protein

How to prepare structures for HADDOCK? – Bonvin Labhttps://www.bonvinlab.org/software/bpg/structures/RosettaDock: 蛋白-蛋白复合物对接预测 - 知乎 (zhihu.com) 要进行LPR1-SEPP1复合物的结合亲和力预测&#xff0c;您可以按照以下步骤进行&#xff1a; 获取蛋白质结…

MySQL的Json类型个人用法详解

前言 虽然MySQL很早就添加了Json类型&#xff0c;但是在业务开发过程中还是很少设计带这种类型的表。少不代表没有&#xff0c;当真正要对Json类型进行特定查询&#xff0c;修改&#xff0c;插入和优化等操作时&#xff0c;却感觉一下子想不起那些函数怎么使用。比如把json里的…

vue实现列表自动滚动效果

效果如图&#xff1a; 1.下载插件 npm install vue-seamless-scroll --save 2.在main.js中引入注册 import scroll from vue-seamless-scroll Vue.use(scroll) 3.在页面中使用&#xff08;写一个固定的表头 el-table:show-header"status" 设置为false,自带的表头不…

嵌入式虚拟仿真实验教学平台使用教程之搭建课程计划

嵌入式虚拟仿真实验教学平台使用教程之创建课程计划 所谓「课程计划」就是将一系列实验按照一定的顺序组织成一个教学计划&#xff0c;和传统的教学计划模式比较类似。接下来我将为大家讲解如何通过该平台创建属于自己的课程计划。 嵌入式虚拟仿真实验教学平台提供了两种创建课…

Python综合案例(基本地图使用)

一、基本地图的使用 基本代码&#xff1a; """ 演示地图可视化的基本使用 """ from pyecharts.charts import Map from pyecharts.options import VisualMapOpts# 准备地图对象 map Map() # 准备数据 data [("北京", 99),("…

js获得相对路径文件,并上传到服务器

如何通过js获得相对路径文件 已知一个相对路径文件&#xff0c;如何使用js将该文件读取为File格式&#xff0c;最后上传到服务器中呢。 1.最简单的解决方案——fetch 代码 import ./index.scss// js通过相对路径获取文件 function FetchGetLocalFile() {const fetchLocalFile …

【0904作业】QT 完成登陆界面跳转到聊天室+完成学生管理系统的查找和删除功能

一、完成登陆界面跳转到聊天室 1> 项目结构 2> 源码 ① .pro ②main #include "mywnd.h" #include"chatCli.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);MyWnd w;w.show();Form f;QObject::co…

【LeetCode算法系列题解】第51~55题

CONTENTS LeetCode 51. N 皇后&#xff08;困难&#xff09;LeetCode 52. N 皇后 II&#xff08;困难&#xff09;LeetCode 53. 最大子序和&#xff08;中等&#xff09;LeetCode 54. 螺旋矩阵&#xff08;中等&#xff09;LeetCode 55. 跳跃游戏&#xff08;中等&#xff09; …

【深入解析spring cloud gateway】07 自定义异常返回报文

Servlet的HttpResponse对象&#xff0c;返回响应报文&#xff0c;一般是这么写的&#xff0c;通过输出流直接就可以将返回报文输出。 OutputStream out response.getOutputStream(); out.write("输出的内容"); out.flush();在filter中如果发生异常&#xff08;例如…

如何使用GPT引领前沿与应用突破之GPT4科研实践技术与AI绘图

GPT对于每个科研人员已经成为不可或缺的辅助工具&#xff0c;不同的研究领域和项目具有不同的需求。例如在科研编程、绘图领域&#xff1a; 1、编程建议和示例代码: 无论你使用的编程语言是Python、R、MATLAB还是其他语言&#xff0c;都可以为你提供相关的代码示例。 2、数据可…

TypeScript_树结构-BST树

树结构 树的特点 树通常有一个根。连接着根的是树干树干到上面之后会进行分叉成树枝&#xff0c;树枝还会分又成更小的树枝在树枝的最后是叶子 树的抽象 树可以模拟生活中的很多场景&#xff0c;比如&#xff1a;公司组织架构、家谱、DOM Tree、电脑文件夹架构 优秀的哈希函…

神策数据 CJO 系列丨解密 CJO:连接体验的下一个前沿趋势

10 余年前&#xff0c;市场营销的焦点聚集在增长黑客如何利用 AARRR 模型&#xff08;获取 Acquisition、激活 Activation、留存 Retention、收入 Revenue、传播 Referral&#xff09;来推动并加速企业的生长发展。我们曾相信&#xff0c;在 AARRR 漏斗中&#xff0c;只要我们吸…

宝塔面板定时监控和重启MySQL数据库(计划任务)

往期教程 如果还有不了解宝塔面板怎么使用的小伙伴&#xff0c;可以看下我总结的系列教程&#xff0c;保证从新手变老鸟&#xff1a; 【建站流程科普】 个人和企业搭建网站基本流程及六个主要步骤常见的VPS主机运维面板汇总—网站运维面板云服务器&#xff0c;VPS&#xff0…

76 # koa 上下文的实现原理

上一节实现了 koa 基本逻辑实现以及属性的扩展&#xff0c;下面继续实现上下文的实现 ctx 跟 proto 的关系 ctx.__proto__.__proto__ protoMDN&#xff1a;defineGetter 备注&#xff1a; 此特性已弃用&#xff0c;建议使用对象初始化语法或 Object.defineProperty() API 来…

《职场情绪稳定:内在的力量与策略》

近期发生的新闻热点&#xff0c;如大规模裁员、创业公司倒闭、公共卫生事件等&#xff0c;让公众更加关注稳定情绪和心理健康的问题。在职场中&#xff0c;我们常常遇到各种挑战和压力&#xff0c;如何保持稳定的情绪成了一个重要的话题。 首先&#xff0c;让我们分享一些工作中…

RecyclerView的smooth scroller -- 诸多案例

作者&#xff1a;snwrking 最近碰到好几个使用LinearSmoothScroll(下方简称为LSS)的场景, 让我对这个类的了解更加进一步, 所以分享在这, 希望对有需要的同学有所帮助. 我个人不太喜欢太理论的东西, 所以整篇文章几乎全是我做过的案例, 也方便也有类似需求的同学对号入座地取用…

【用unity实现100个游戏之8】用Unity制作一个炸弹人游戏

文章目录 前言素材开始一、绘制地图二、玩家设置三、玩家移动四、玩家四方向动画运动切换 五、放置炸弹六、生成爆炸效果七、墙壁和可破坏障碍物的判断八、道具生成和效果九、玩家死亡十、简单的敌人AI十一、虚拟摇杆 待续源码完结 前言 我们将在这个视频中&#xff0c;学习如…

Oracle 遍历变量游标

背景 由于我们的数据库系统中的游标特别多&#xff0c;DBA让我们优化&#xff0c;减少游标的使用。 电脑系统&#xff1a;windows数据库&#xff1a;Oracle数据库图形化界面工具&#xff1a;Toad&#xff0c;DBeaver(我測試的時候用的)记录日期&#xff1a;2023-09-04 具体实…