杂项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树结构:

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
自定义注解—防重复提交-拦截器实现
在前置方法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')")
注解
- @PostConstruct — 后置构造器:表示在构造器之后
Java提供: @PostConstruct注解被用来修饰一个非静态的void()
非静态的原因是
@PostConstruct注解标记的方法会在构造器之后执行,静态方法会在构造方法执行前执行完毕
方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行
执行顺序: Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
- @PreDestroy
Java提供: 被@PreDestroy修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreDestroy修饰的方法会在destroy()方法之后运行,在Servlet被彻底卸载之前
执行顺序: 调用destroy()方法->@PreDestroy->destroy()方法->bean销毁
序列号
private static final long serialVersionUID = -8970718410437077606L;
通常在类最前面会指定序列版本号, 原因如下:
-
如果没有定义一个名为serialVersionUID,类型为long的变量,Java序列化机制会根据编译的class自动生成一个serialVersionUID,即
隐式声明。这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID 。此时如果对某个类进行修改的话,那么版本上面是不兼容的,就会出现反序列化报错的情况 -
在实际的开发中,重新编译会影响项目进度部署,所以我们为了提高开发效率,不希望通过编译来强制划分软件版本,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化
-
序列化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
开发运维, 实现开发运维一体化, 高效交付
生命周期:
-
持续计划
-
持续开发
-
持续测试
-
持续集成
-
持续交付
-
持续部署
-
持续监控
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”
流程:
- 前端传递数据给后端,通过vue的数据双向绑定将用户输入的数据绑定给前端定义的参数,点击相应的按钮携带参数发送axiox异步请求
- 后端通过参数接受,比如说登录表单,后端使用Post方式接受,@RequestBody注解接受表单数据将其转化为实体类对象user,主要在controller层,然后在controller层注入service层bean调用相应的逻辑方法
- service层的方法主要编写业务逻辑代码,比如:从user中取出需要的字段,进行字段校验一般是非空或格式校验,从数据库查询对应的数据比对,成功则跳转首页,失败返回相应提示
- 如何从mapper层查询数据库主要涉及到mapper文件的SQL编写,自定义实体类字段和数据库列的映射,选择查询哪些字段,如何连表,使用
标签判断非空 - 如果有其它权限验证,
如果在方法上有注解之类的,在执行方法前会先执行自定义的拦截代码,在防重复提交的注解中使用拦截器实现,重写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可以执行执行操作或脚本或会话

浙公网安备 33010602011771号