杂项05

MVVM双向绑定之核心原理

原文链接

MVVM可视为MVC的增强版

JS 几个流行的框架 Vuejs、Ember.js、AngularJS 都使用 MVVM 模式,该模式叫做视图模型双向数据绑定,以达到数据和视图快速同步的目的

双向绑定的概念:

  • 从数据到视图, 数据变化视图也会发生变化
  • 从视图到数据, 视图变化数据也会发生变化; 例如输入框的内容发生变化传递的值也会变化

这是通过监听DOM改变实现的

MVVM 拆开来是 Model-View-ViewModel,View,ViewModel,Model 三部分组成,它是一种前端开发的架构模式

一、ViewModel将改变传给Controller,Controller定位到需要修改的View部分并改变这部分
二、ViewModel包揽了Controller的数据处理功能之後,由于Controller的存在,原本的一个大视图的控制与处理,被Controller切割成了很多小的ViewModel和Model的编写问题,每一个View、ViewModel和Model组成了一个单独的单元,问题规模变小,问题就更容易处理了
三、数据绑定是,将视图中的某个小组件(View)、小组件的处理函数(ViewModel)、小组件相关的数据(Model)互相绑定起来。原本大Controller的处理是收到一个事件後,Controller需要从整个Model的顶端一层层下来,找到对应的数据进行计算,计算完成後,又从document对象上,一层层找下来,找到对应的小组件进行修改。每一个数据查找和视图修改操作,都需要从全局空间找下来。进行数据绑定之後,所有的这些都在局部空间操作,不再经过全局空间,所以代码看起来就舒服很多

JavaScript

文档对象模型DOM是HTML和XML文档的编程接口

DOM树结构:

DOM HTML tree

vue

v-bind:属性绑定(简写:), v-on:事件绑定(简写@), v-model:双向绑定

v-bind与v-model都是绑定vue中data中的属性的,他们最主要的区别是v-bind的绑定只是单向的,他会将data中的数据投影到绑定的地方,在被绑定的地方对数据修改时,data中的原始数据是不会改变的,而v-model的绑定是双向的,不仅将data中的数据对标签内进行绑定,还会将标签中的数据反向绑定到data中,标签数据改变后data中的数据也会同步改变。

v-on绑定的是事件(函数)是vue中methods中的数据,触发v-on绑定,就会执行其所绑定的事件

钩子函数

created()和mounted()

ES6

ES6基本语法以及let和var区别

自定义注解—防重复提交-拦截器实现

在前置方法preHandle中拿到handler对象, 判断是否是一个HandlerMethod实例, 拿到方法拿到方法上的RepeatSubmit.class注解, 不为空就说明此方法有重复提交限制不能重复提交, 需要做检查

核心方法是isRepeatSubmit()—检查是否是实例-可重复读取inputStream的request-是则工具类把输入流转成一行字符串,否则toJSONString

// try后面加括号, 从java1.7版本开始,支持使用try后面跟随()括号管理释放资源,前提是这些可关闭的资源必须实现 java.lang.AutoCloseable 接口。
//这样更加简单, 无需再在finally里关闭资源
try (InputStream inputStream = request.getInputStream()){
    
}catch(Exception e){
    
}finally{
    
}

自定义注解—限流-AOP实现

统计方法限流

    @Before("@annotation(rateLimiter)")
    public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
    {
        
    }
// ss是相对于给这个权限类Bean取一个别名, 方便注入到其他类中使用, 不加默认是类名首字母小写
@Service("ss")
public class PermissionService
{
    
}
// 比如这样使用
@PreAuthorize("@ss.hasPermi('system:dict:add')")

注解

  1. @PostConstruct — 后置构造器:表示在构造器之后

Java提供: @PostConstruct注解被用来修饰一个非静态的void()

非静态的原因是@PostConstruct注解标记的方法会在构造器之后执行,静态方法会在构造方法执行前执行完毕

方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行

执行顺序: Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)

  1. @PreDestroy

Java提供: 被@PreDestroy修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreDestroy修饰的方法会在destroy()方法之后运行,在Servlet被彻底卸载之前

执行顺序: 调用destroy()方法->@PreDestroy->destroy()方法->bean销毁

序列号

private static final long serialVersionUID = -8970718410437077606L;

通常在类最前面会指定序列版本号, 原因如下:

  1. 如果没有定义一个名为serialVersionUID,类型为long的变量,Java序列化机制会根据编译的class自动生成一个serialVersionUID,即隐式声明。这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID 。此时如果对某个类进行修改的话,那么版本上面是不兼容的,就会出现反序列化报错的情况

  2. 在实际的开发中,重新编译会影响项目进度部署,所以我们为了提高开发效率,不希望通过编译来强制划分软件版本,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化

  3. idea序列号设置

  4. 序列化ID设置是为了序列化和反序列化成功而存在的,实现Serializable接口时,不是必须要有Serializable id,但建议为每个可序列化的类都提供一个Serializable id。这个id可以保证在序列化和反序列化过程中,对象的唯一性和一致性

Excel注解

commo/annotation下的Excel注解是自定义的, 工具类

我自己是使用的POI依赖

<!-- excel工具 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
</dependency>

DevOps

开发运维, 实现开发运维一体化, 高效交付

生命周期:

  1. 持续计划

  2. 持续开发

  3. 持续测试

  4. 持续集成

  5. 持续交付

  6. 持续部署

  7. 持续监控

DevOps三大原则是指:

  • 流动原则(Flow):DevOps强调从业务角度来考虑软件开发和运维的过程,通过优化价值流,从而加速业务价值的交付。流动原则包括以下几点:消除浪费,优化价值流,保持流程可视化和工作标准化。

  • 反馈原则(Feedback):DevOps强调快速反馈,通过及早发现和解决问题,提高软件的质量和稳定性。反馈原则包括以下几点:建立快速反馈机制,提高问题解决速度,强调团队沟通和协作,实现团队共同学习。

  • 持续学习与实验原则(Continuous Learning and Experimentation):DevOps强调团队持续学习和实验,不断改进软件开发和运维的工作流程。持续学习与实验原则包括以下几点:鼓励团队学习和实验,倡导开放式沟通和知识共享,推进自动化和标准化,不断改进工作流程和流程规范

某块开发详解,前后端交互数据存储

补充点详细的地方,就风功率预测的 某一块开发详细写一下。比如详细写一个前后端的交易,数据的交互存储

现在的开发模式前后端分离,开发者只需要专注干他所擅长的事,效率也能够得到提升,所以前后端开发过程中,前端人员负责页面展示和数据获取,后端人员负责业务逻辑处理和接口封装,在Java后端开发中流行Restful风格编程,前后端传递数据最常用的数据格式是json;

获取列表使用GET,表单提交一般使用POST,删除数据使用DELETE,修改数据使用PUT

接收路径参数使用@PathVariable;接受后面的k-v数据使用@RequestParam ,接收对象使用@RequestBody

数据交互常使用一些参数接受注解:常用@RequestBody获取请求体里面的数据,(获取请求头数据使用@RequestHeader,获取Cookie里的值用@CookieValue)

  • @RequestBody,它是用来处理前台定义发来的数据Content-Type: 而不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;使用@RequestBody注解接收参数的时候,从名称上来看也就是说要读取的数据在请求体里,前台的Content-Type必须要改为application/json,所以要发post请求,因为Ajax使用的POST,并且发送的是JSON对象。前端必须指定请求json数据的contentType为:application/json,否则会报类型不支持的异常错误“org.sp ringframework.web.HttpMediaTypeNotSupportedException”

流程:

  1. 前端传递数据给后端,通过vue的数据双向绑定将用户输入的数据绑定给前端定义的参数,点击相应的按钮携带参数发送axiox异步请求
  2. 后端通过参数接受,比如说登录表单,后端使用Post方式接受,@RequestBody注解接受表单数据将其转化为实体类对象user,主要在controller层,然后在controller层注入service层bean调用相应的逻辑方法
  3. service层的方法主要编写业务逻辑代码,比如:从user中取出需要的字段,进行字段校验一般是非空或格式校验,从数据库查询对应的数据比对,成功则跳转首页,失败返回相应提示
  4. 如何从mapper层查询数据库主要涉及到mapper文件的SQL编写,自定义实体类字段和数据库列的映射,选择查询哪些字段,如何连表,使用标签判断非空
  5. 如果有其它权限验证,

如果在方法上有注解之类的,在执行方法前会先执行自定义的拦截代码,在防重复提交的注解中使用拦截器实现,重写preHandle方法,拿到方法上的注解,如果有—>判断是否是一个重复提交的请求,重复提交则提示不允许重复提交,返回false不放行,否则返回true放行;

具体的判断是否重复提交的逻辑是:判断请求url和数据是否和上次相同,拼接key,从redis中取出数据比较数据和时间

动态数据源

多数据源就是在一个应用中配置多个不同的连接池,连接不同的数据库。即在xml中配置多个sqlSessionFactory,这种情况会造成如果应用中数据源比较多,那么建立的多个连接池就会在一定程度上消耗资源

动态数据源就是实现抽象类AbstractRoutingDataSource中的determineCurrentLookupKey方法,然后通过注解方式动态改变数据源。动态数据源的优势就是不想多数据源那样造成资源浪费,但是对业务代码侵入大

在我们企业项目开发的过程中,有的时候,一个项目需要在运行时,根据某种条件(比如注解、方法名等)选择使用哪个数据源

通过配置多个数据源和使用AOP切面,在运行时动态切换数据源,实现了动态切换数据源的功能

注解

切面定义

@within和@annotation的区别:

  • @within 对象(Bean)级别
  • @annotation 方法级别
// 表示切标注了@RestController注解的类
@Around("@within(org.springframework.web.bind.annotation.RestController") 
        这个用于拦截标注在类上面的@RestController注解

// 表示切标注了该注解的方法,当然示例注解不能标注在方法级别
@Around("@annotation(org.springframework.web.bind.annotation.RestController") 
         这个用于拦截标注在方法上面的@RestController注解
            
// 有且仅有一个参数并且参数上类型上有Transactional注解
@args(org.springframework.transaction.annotation.Transactional)

其他

// 定义在cn.freemethod.business.pack.Say接口中的方法
execution(* cn.freemethod.business.pack.Say.*(..))

// 任何cn.freemethod.business包中的方法
execution(* cn.freemethod.business.*.*(..))

// 任何在com.xyz.service包中的方法
within(com.xyz.service.*)

// 任何目标对象实现了com.xyz.service.AccountService的方法
target(com.xyz.service.AccountService)

// 有且只有一个Serializable参数的方法
args(java.io.Serializable)

// bean的名字为tradeService中的方法
bean(simpleSay)
  
// bean名字匹配*Impl的bean中的所有方法
bean(*Impl)

@Log

日志注解@Log,实现的步骤是定义一个日志注解,包含需要记录的哪些字段,在framework包下的aspect包下添加一个日志切面类,使用@Aspect注解开启AOP,使用@Component将该Bean将给Spring管理,切面选择标注了@Log注解的方法,使用ThreadLocal

private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");

保存每个线程的方法开始时间,最后在finally中使用TIME_THREADLOCAL.remove()释放内存占用

@RateLimiter

限流注解@RateLimiter同样也是通过AOP切面的方式实现方法限流,但是这里使用了redisTemplate的执行脚本的方法

// 返回一个只包含指定元素的List,在某些特殊需求下不会造成空间浪费
List<Object> keys = Collections.singletonList(combineKey);

如果频繁地使用Redis,比如在 for循环中调用 redis,有时可能会报错: Could not get a resource from the pool。

这是因为 Redis的连接数是有限的,打开了Redis的连接,用完记得要关闭,如果连接数不够了就会报错。

Redis 批量操作,可以使用 RedisTemplate 的 execute()方法,execute() 方法,可以在一次连接中进行多个命令操作。执行完会自动关闭连接。

redisTemplate.execute可以执行执行操作或脚本或会话
posted @ 2024-03-13 14:57  好滴都  阅读(32)  评论(0)    收藏  举报