技术宅小白

技术宅小白 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织 www.force0521.icu 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

技术宅小白 发布了文章 · 1月13日

JSON的格式类型到底有哪些呢?

JSON是目前最流行的一种数据交换格式,对于它我们有必要非常熟悉它的各方面知识,这次我们来看看它的格式类型有哪些。

数据交换格式方式

  • 基本类型
  • 数组类型
  • 对象嵌套

案例实操

基本类型

{"键" : 值, "键" : "值",...},以大括号开始,键的名称加上冒号,然后跟上对应的的值,若有其他键值对则以逗号进行分割。

{
 "name": "张三",
 "age": 18,
 "sex": true
}

数组类型

[{"键" : 值, "键" : "值"},{"键" : 值, "键" : "值"},...],以中括号开始,其间的数据通过逗号进行分割。

[
 {
 "name": "张三",
 "age": 18,
 "sex": true
 },
 {
 "name": "李四",
 "age": 19,
 "sex": false
 }
]

对象嵌套

由上面两种类型,因为值的不固定性,可以演变出各种各样的嵌套类型。

{
 "name": "teacher",
 "computer": {
 "CPU":"intel7,
 "disk": "512G"
 },
 "students": [
 {
 "name": "张三",
 "age": 18,
 "sex": true
 },
 {
 "name": "李四",
 "age": 19,
 "sex": false
 }
 ]
}

更多细节以及要注意的格式还可以直接在JSON官网查看。

扩展~XML

XML也是一种数据交换格式,它不是指一门语言,而是指跨语言的数据格式,目前JSON正慢慢取代它的地位,但在各个地方我们还是能经常见到,所以了解它也是我们的必修之课,我们也来看看它的语法格式规则。

所有 XML 元素都须有关闭标签

在 HTML,经常会看到没有关闭标签的元素:

<p>This is a paragraph
<p>This is another paragraph

在 XML 中,省略关闭标签是非法的。所有元素都_必须_有关闭标签:

<p>This is a paragraph</p>
<p>This is another paragraph</p> 

注释:您也许已经注意到 XML 声明没有关闭标签。这不是错误。声明不属于XML本身的组成部分。它不是 XML 元素,也不需要关闭标签。

XML 标签对大小写敏感

XML 元素使用 XML 标签进行定义。

XML 标签对大小写敏感。在 XML 中,标签 <Letter> 与标签 <letter> 是不同的。

必须使用相同的大小写来编写打开标签和关闭标签:

<Message>这是错误的。</message>
​
<message>这是正确的。</message> 

注释:打开标签和关闭标签通常被称为开始标签和结束标签。不论您喜欢哪种术语,它们的概念都是相同的。

XML 必须正确地嵌套

在 HTML 中,常会看到没有正确嵌套的元素:

<b><i>This text is bold and italic</b></i>

在 XML 中,所有元素都_必须_彼此正确地嵌套:

<b><i>This text is bold and italic</i></b>

在上例中,正确嵌套的意思是:由于 元素是在 元素内打开的,那么它必须在 元素内关闭。

XML 文档必须有根元素

XML 文档必须有一个元素是所有其他元素的_父元素_。该元素称为_根元素_。

<root>
 <child>
 <subchild>.....</subchild>
 </child>
</root>

XML 的属性值须加引号

与 HTML 类似,XML 也可拥有属性(名称/值的对)。

在 XML 中,XML 的属性值须加引号。请研究下面的两个 XML 文档。第一个是错误的,第二个是正确的:

<note date=08/08/2008>
 <to>George</to>
 <from>John</from>
</note> 
<note date="08/08/2008">
 <to>George</to>
 <from>John</from>
</note> 

在第一个文档中的错误是,note 元素中的 date 属性没有加引号。

查看原文

赞 0 收藏 0 评论 0

技术宅小白 发布了文章 · 1月12日

解决vue页面刷新,数据丢失

在做vue项目的过程中有时候会遇到一个问题,就是进行页面刷新的时候,页面的数据会丢失,出现这个问题的原因是因为当用vuex做全局状态管理的时候,store中的数据是保存在运行内存中的,页面刷新时会重新加载vue实例,store中的数据就会被重新赋值,因此数据就丢失了,解决方式如下:

解决方法一:

最先想到的应该就是利用localStorage/sessionStorage将数据储存在外部,做一个持久化储存,下面是利用localStorage存储的具体方案:

方案一:由于state中的数据是响应式的,而数据又是通过mutation来进行修改,故在通过mutation修改state中数据的同时调用localStorage.setItem()方法来进行数据的存储。

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
    state: {
       orderList: [],
       menuList: []
   },
    mutations: {
        orderList(s, d) {
          s.orderList= d;
          window.localStorage.setItem("list",jsON.stringify(s.orderList))
        },  
        menuList(s, d) {
          s.menuList = d;
          window.localStorage.setItem("list",jsON.stringify(s.menuList))
       },
   }
})

在页面加载的时候再通过localStorage.getItem()将数据取出放回到vuex,可在app.vue的created()周期函数中写如下代码:

if (window.localStorage.getItem("list") ) {
        this.$store.replaceState(Object.assign({}, 
        this.$store.state,JSON.parse(window.localStorage.getItem("list"))))
}

方案二:方案一能够顺利解决问题,但不断触发localStorage.setItem()方法对性能不是特别友好,而且一直将数据同步到localStorage中似乎就没必要再用vuex做状态管理,直接用localStorage即可,于是对以上解决方法进行了改进,通过监听beforeunload事件来进行数据的localStorage存储,beforeunload事件在页面刷新时进行触发,具体做法是在App.vue的created()周期函数中下如下代码:

if (window.localStorage.getItem("list") ) {
        this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(window.localStorage.getItem("list"))))
    } 

window.addEventListener("beforeunload",()=>{
        window.localStorage.setItem("list",JSON.stringify(this.$store.state))
    })

解决方法二(推荐):

这个方法是基于对computed计算属性的理解,在vue的官方文档中有这么一段话:

我们可以将同一函数定义为一个方法而不是一个计算机属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要message还没有发生改变,多次访问reversedMessage计算属性会立即返回之前的计算结果,而不必再次执行函数。

由此得知计算属性的结果会被缓存,也就是说在有缓存的情况下,computed会优先使用缓存,于是也可以在state数据相对应的页面这样写:

computed:{
   orderList() {
       return this.$store.state.orderList
   }
}

文章来自网络,侵删

查看原文

赞 1 收藏 0 评论 0

技术宅小白 发布了文章 · 1月11日

使用Spring Boot Mybatis 搞反向工程,简直不要太方便

1. 拷贝 Mybatis 反向工程配置文件到项目的根目录下
在这里插入图片描述
2. 根据项目及表的情况,修改 GeneratorMapper.xml 配置

  • 如果使用 高版本 , 驱动类变为:com.mysql.cj.jdbc.Driver
  • url 后面应该加属性 nullCatalogMeansCurrent=true ,否则生成有问题
当前版本 MySQL 数据库为 5.7

主要根据注释来修改自己的内容

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE generatorConfiguration  
  
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"  
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">  
<generatorConfiguration>  
    <!-- 指定连接数据库的 JDBC 驱动包所在位置,指定到你本机的完整路径 -->  
    <classPathEntry location="E:\Java\tool\maven_repository\mysql\mysql-connector-java\5.1.9\mysql-connector-java-5.1.9.jar"/>  
  
  
  
    <!-- 配置 table 表信息内容体,targetRuntime 指定采用 MyBatis3 的版本 -->  
    <context id="tables" targetRuntime="MyBatis3">  
        <!-- 抑制生成注释,由于生成的注释都是英文的,可以不让它生成 -->  
        <commentGenerator>  
            <property name="suppressAllComments" value="true"/>  
        </commentGenerator>  
        <!-- 配置数据库连接信息 -->  
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"  
                        connectionURL="jdbc:mysql://localhost:3306/springboot"  
                        userId="root"  
                        password="123456">  
        </jdbcConnection>  
  
  
  
  
        <!-- 生成 model 类,targetPackage 指定 model 类的包名, targetProject 指定  
        生成的 model 放在 IDEA 的哪个工程下面-->  
        <javaModelGenerator targetPackage="com.md.springboot.model"  
                            targetProject="src/main/java">  
            <property name="enableSubPackages" value="false"/>  
            <property name="trimStrings" value="false"/>  
        </javaModelGenerator>  
  
  
  
  
        <!-- 生成 MyBatis 的 Mapper.xml 文件,targetPackage 指定 mapper.xml 文件的  
        包名, targetProject 指定生成的 mapper.xml 放在 IDEA 的哪个工程下面 -->  
        <sqlMapGenerator targetPackage="com.md.springboot.mapper"  
                         targetProject="src/main/java">  
            <property name="enableSubPackages" value="false"/>  
        </sqlMapGenerator>  
  
  
  
  
  
        <!-- 生成 MyBatis 的 Mapper 接口类文件,targetPackage 指定 Mapper 接口类的包  
        名, targetProject 指定生成的 Mapper 接口放在 IDEA 的哪个工程下面 -->  
        <javaClientGenerator type="XMLMAPPER"  
                             targetPackage="com.md.springboot.mapper" targetProject="src/main/java">  
            <property name="enableSubPackages" value="false"/>  
        </javaClientGenerator>  
  
  
  
  
  
        <!-- 数据库表名及对应的 Java 模型类名,有几个表写几个table -->  
        <table tableName="t_student" domainObjectName="Student"  
               enableCountByExample="false"  
               enableUpdateByExample="false"  
               enableDeleteByExample="false"  
               enableSelectByExample="false"  
               selectByExampleQueryId="false"/>  
  
  
    </context>  
</generatorConfiguration>  

此时会报错,如下
在这里插入图片描述
这个时候可以不用理会,项目也是会正常运行的

Spring Boot 理论+实战系列教程大家看这个:

3. 在pom.xml 文件中添加 mysql 反向工程依赖

<build>  
    <plugins>  
        <!--mybatis 代码自动生成插件-->  
        <plugin>  
            <groupId>org.mybatis.generator</groupId>  
            <artifactId>mybatis-generator-maven-plugin</artifactId>  
            <version>1.3.6</version>  
            <configuration>  
                <!--配置文件的位置-->  
                <configurationFile>GeneratorMapper.xml</configurationFile>  
                <verbose>true</verbose>  
                <overwrite>true</overwrite>  
            </configuration>  
        </plugin>  
    </plugins>  

</build>  

4. 双击生成相关文件
在这里插入图片描述
5. 生成的文件
自动生成model/Student、实体类
以及StudentMapper,接口
StudentMapper.xml 具体对数据库的操作
这样方便我们使用,具体的下面详细介绍,注意看注释
在这里插入图片描述
Student

package com.md.springboot.model;  
  
public class Student {  
    private Integer id;  
  
    private String name;  
  
    private Integer age;  
  
    public Integer getId() {  
        return id;  
    }  
  
    public void setId(Integer id) {  
        this.id = id;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Integer getAge() {  
        return age;  
    }  
  
    public void setAge(Integer age) {  
        this.age = age;  
    }  
}  

StudentMapper

package com.md.springboot.mapper;  
  
import com.md.springboot.model.Student;  
  
public interface StudentMapper {  
    int deleteByPrimaryKey(Integer id);  
  
    int insert(Student record);  
  
    int insertSelective(Student record);  
  
    Student selectByPrimaryKey(Integer id);  
  
    int updateByPrimaryKeySelective(Student record);  
  
    int updateByPrimaryKey(Student record);  
}  

StudentMapper.xml

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="com.md.springboot.mapper.StudentMapper">  
  
  
  <!--  
    数据库字段名称     实体对象属性名称  
    user_name           userName  
    user_age            userAge  
  
  -->  
  <!--  
    如果数据表中的字段是多个单词构成的,通过Mybatis逆向工程生成的对象属性名称  
    会按照驼峰命名法的规则生成属性名称  
    自己设计数据表的时候,多个单词之前使用下划线分隔  
  
  -->  
  
  <!--  
    resultMap的作用  
    1. 当数据库中的字段名称和实体类对象的属性名不一致,可以进行转换  
    2. 当前查询的结果对象没有对应一个表时,可以自定义一个结果集  
  -->  
  <resultMap id="BaseResultMap" type="com.md.springboot.model.Student">  
    <!--  
      id标签只能修饰主键字段,result标签修饰其他字段  
      column 数据库中的字段名称  
      property 映射对象的属性名称  
      jdbcType 对应的类型  
    -->  
    <id column="id" jdbcType="INTEGER" property="id" />  
    <result column="name" jdbcType="VARCHAR" property="name" />  
    <result column="age" jdbcType="INTEGER" property="age" />  
  </resultMap>  
  
  
  <!--sql语句片段,将公共部分抽出-->  
  <sql id="Base_Column_List">  
    id, name, age  
  </sql>  
  
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">  
    select   
    <include refid="Base_Column_List" />  
    from t_student  
    where id = #{id,jdbcType=INTEGER}  
  </select>  
  
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">  
    delete from t_student  
    where id = #{id,jdbcType=INTEGER}  
  </delete>  
  
  <insert id="insert" parameterType="com.md.springboot.model.Student">  
    insert into t_student (id, name, age  
      )  
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}  
      )  
  </insert>  
  
  
  <!--动态sql-->  
  <insert id="insertSelective" parameterType="com.md.springboot.model.Student">  
    insert into t_student  
    <trim prefix="(" suffix=")" suffixOverrides=",">  
      <if test="id != null">  
        id,  
      </if>  
      <if test="name != null">  
        name,  
      </if>  
      <if test="age != null">  
        age,  
      </if>  
    </trim>  
    <trim prefix="values (" suffix=")" suffixOverrides=",">  
      <if test="id != null">  
        #{id,jdbcType=INTEGER},  
      </if>  
      <if test="name != null">  
        #{name,jdbcType=VARCHAR},  
      </if>  
      <if test="age != null">  
        #{age,jdbcType=INTEGER},  
      </if>  
    </trim>  
  </insert>  
  
  
  <update id="updateByPrimaryKeySelective" parameterType="com.md.springboot.model.Student">  
    update t_student  
    <set>  
      <if test="name != null">  
        name = #{name,jdbcType=VARCHAR},  
      </if>  
      <if test="age != null">  
        age = #{age,jdbcType=INTEGER},  
      </if>  
    </set>  
    where id = #{id,jdbcType=INTEGER}  
  </update>  
  
  <update id="updateByPrimaryKey" parameterType="com.md.springboot.model.Student">  
    update t_student  
    set name = #{name,jdbcType=VARCHAR},  
      age = #{age,jdbcType=INTEGER}  
    where id = #{id,jdbcType=INTEGER}  
  </update>  
</mapper>  
查看原文

赞 0 收藏 0 评论 0

技术宅小白 发布了文章 · 1月8日

Nginx只能负载均衡?不、不、不;它比你想象的还要强大!

image

Nginx应该是现在最火的web和反向代理服务器,没有之一。她是一款诞生于俄罗斯的高性能web服务器,尤其在高并发情况下,相较Apache,有优异的表现。那除了负载均衡,她还有什么其他的用途呢,下面我们来看下。
一、负载均衡
Nginx通过反向代理可以实现服务的负载均衡,避免了服务器单节点故障,把请求按照一定的策略转发到不同的服务器上,达到负载的效果。常用的负载均衡策略有:
除了负载均衡,Nginx还可以做很多,限流、缓存、黑白名单等

  1. 轮询

将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载。

  1. 加权轮询

不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请;而配置低、负载高的机器,给其分配较低的权重,降低其系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。

  1. ip_hash(源地址哈希法)

根据获取客户端的IP地址,通过哈希函数计算得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客户端要访问服务器的序号。采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问。

  1. 随机

通过系统的随机算法,根据后端服务器的列表大小值来随机选取其中的一台服务器进行访问。

  1. least_conn(最小连接数法)

由于后端服务器的配置不尽相同,对于请求的处理有快有慢,最小连接数法根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前的请求,尽可能地提高后端服务的利用效率,将负责合理地分流到每一台服务器。

二、限流
Nginx的限流模块,是基于漏桶算法实现的,在高并发的场景下非常实用。
image
1、配置参数
1)limit_req_zone定义在http块中,binary_remote_addr 表示保存客户端IP地址的二进制形式。
2)Zone定义IP状态及URL访问频率的共享内存区域。zone=keyword标识区域的名字,以及冒号后面跟区域大小。16000个IP地址的状态信息约1MB,所以示例中区域可以存储160000个IP地址。
3)Rate定义最大请求速率。示例中速率不能超过每秒100个请求。
2、设置限流
burst排队大小,nodelay不限制单个请求间的时间。
三、静态代理
Nginx擅长处理静态文件,是非常好的图片、文件服务器。把所有的静态资源的放到nginx上,可以使应用动静分离,性能更好。
四、缓存
1、浏览器缓存,静态资源缓存用expire。

location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)${
expires   7d;
}
location ~ .*l.(?:js |css)$ {
expires   7d;
}

2、代理层缓存

proxy_cache_path /data/cache/nginx/ levels=1:2 keys_zone=cache:512m inactive = 1d max_size=8g

location / {
    location~ l.(htm | html)?$ {
         proxy_cache cache;
         proxy_cache key$uri$is_args$args;   //以此变量值做HASH,作为KEY
         add_header X-Cache $upstream_cache_status;
         proxy_cache_valid 200 10m;
         proxy_cache_valid any 1m;
         proxy_pass http: //real_server;
         proxy redirectoff;
     }
     location~ .*l.(gif |jpgljpeg |bmp|png|ico |txtljs |css)$ {
          root /data/webapps/edc;
          expires     3d;
          add_header Static Nginx-Proxy;
      }
}

五、黑白名单
1、不限流白名单
image
2、黑名单

location / {
    deny 10.52.119.21;
    deny 122.12.1.0/24;
    allow 10.1.1.0/16;
    allow 1001: 0db8: :/32;
    deny all;
}

好了,上面就是nginx几个常用功能,静态分离、负载均衡、限流、缓存、黑白名单等,你都了解了吗?

查看原文

赞 0 收藏 0 评论 0

技术宅小白 发布了文章 · 1月7日

应届生,请通过Github找到了能打败毕设的“宝藏”

在这里插入图片描述

前言

对于程序员而言,GitHub是一个宝藏男孩,为什么大家会把自己的辛苦写出来的源码挂到GitHub上呢?拿出卖钱它不香吗?其实对于这个问题,下面这张图做了很好的阐释:

img

说到底,开源是利他利己的,比如

  • 音乐是分享给大家免费听的,听音乐本身并不需要钱,听电台就是。你想听什么就听什么,还可以用各种音效工具给增强你的视听享受,或者拿来招徕顾客,为你的作品烘托情绪,这些是要钱的
  • 书本也是分享给大家免费看的,去图书馆就是,借书收取的费用其实只是维持图书馆的正常运转和防止你无限期的独占图书资源而
说白了就是认为开放比封闭能够更大化社会总福利并为之付诸行动的精神,就是我们所提倡的共产主义。各尽所能,各取所需!

互联网世界是一块试金石,不受欢迎的作品很快就湮灭在浩瀚的海洋里;而广受群众喜爱的作品,一定能冉冉升起、熠熠生辉。

开源而不是闭门造车,可以与千千万万的程序员交流并获得反馈,在交流与反馈中可以进一步提高代码质量,每一位使用自己开源代码的程序员,同时也是QA工程师,可以帮助开源代码发现很多隐藏的BUG,到哪里找不要工资的测试工程师噢!有百利而无害,何乐而不为。

钱是永远赚不完的,只有放眼未来,立足长远,才能赚更多的钱!

通过GitHub找到我们需要的毕设

​ 很多人通过GitHub去找现成的毕设项目,但是很多是够我们发现,找到的毕业设计的代码都根本跑步起来,或者是太古老了,比如象这样的:
在这里插入图片描述

这样的:在这里插入图片描述

还有这样的:
在这里插入图片描述
<span style="color:red;font-size:24px;">Tips:不下载也知道代码中的业务完全不够看的,还需要下载,配置环境,麻烦的要死。</span>

​ 当然也有人通过国内的码云去找的,但是找到的结果是这样的:

这样的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6lq2ynZI-1610007739292)(img\14.jpg)]

<span style="color:red;font-size:24px;">你给老子说说我下载下来能干啥?</span>

这样的:
在这里插入图片描述
<span style="color:red;font-size:24px;">你们要搞哪样呀。。。。杀了我吧。</span>

还有这样的:
在这里插入图片描述

<span style="color:red;font-size:24px;">就没有一个能用的,小编心里一整MMP。</span>

小编通过3个月努力,整合了目前市面上所有毕设

他们长这样:
在这里插入图片描述

这样:
在这里插入图片描述

这样:
在这里插入图片描述

还有这样:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<span style="color:red;font-size:25px;font-weight:bold;backgroud-color:blue;"> 累计毕设项目大致2600多篇,全部都软件工程方向,所有代码都已经保证能够运行,而且,而且,如果你还有问题,可以私信小编,小编在力所能及的范围内可以帮助你进行调试,但是请素质三连。</span>

01-宿舍管理系统
02-基于Python完成情感分析
03-电商项目
04-基于Opencv的车牌识别系统
05-基于HTML5的实时聊天工具的设计与实现
06-基于RestFul点餐系统
07-基于PHP毕设选题系统
08-音乐推荐系统
09-校园即时服务平台
10-微书--小程序阅读应用
11-秀视频--小程序社交软件
12-基于流程监控的本科毕业设计管理系统
13-基于Android的天气APP
14-毕业设计管理系统
15-计算机专业认证在线考试系统
16-企业OA后台管理系统
17-防盗门进销存管理系统(SDIMS)
18-聊天系统
19-物业管理平台后台
20-基于Java 中 SSH 框架的 物流配送管理系统

**写在结尾:感谢大家看到结束;
如果你有需要,请关注B站UP主:忘不了的Final,希望能够帮到你
请私聊小编,发送毕业设计,届时就可以收到相关回复。**

查看原文

赞 0 收藏 0 评论 0

技术宅小白 发布了文章 · 1月6日

JDK 16 即将发布,新特性速览!

你还能追上 Java 的更新速度吗?

当开发者深陷 Java 8 版本之际,这边下一版本 Java 16 有了最新的消息,与 Java 15 一样,作为短期版本,Oracle 仅提供 6 个月的支持。

根据发布计划,JDK 16 将在 12 月 10 日和 2021 年 1 月 14 进入 Rampdown 阶段,2021 年 2 月 4 日到 2 月 18 日进入发布候选阶段。最终版本预计于 2021 年 3 月 16 日正式发布。

日前, JDK 16 揭晓了即将到来的新功能,接下来,我们将一睹为快:

  • 以前在 JDK 15 中预览的密封类和接口限制其他类和接口可以扩展或实现它们。该计划的目标包括,允许类或接口的作者控制负责实现它的代码,提供比访问修饰符更声明性的方式来限制超类的使用,以及通过提供模式分析的基础来支持模式匹配的未来方向。
  • 默认情况下,对 JDK 内部进行强封装,但关键内部 API(如 misc.Unsafe ) 除外。用户可以选择自 JDK 9 以来默认的宽松强封装。此建议的目标包括提高 JDK 的安全性和可维护性,作为项目 Jigsaw 的一部分,并鼓励开发人员从使用内部元素迁移到使用标准 API,以便开发人员和最终用户都可以轻松地更新到未来的 Java 版本。
  • 外部链接程序 API,提供静态类型、纯 Java 对本机代码的访问。此 API 将在 JDK 16 中处于孵化器阶段。
  • 将 ZGC(Z 垃圾收集器)线程堆栈处理从安全点移动到并发阶段。此计划的目标包括从 ZGC 安全点中删除线程堆栈处理。
  • 弹性元空间功能,它将可以更迅速地将未使用的 HotSpot VM 类元数据(元空间)内存返回到操作系统,减少元空间占用空间并简化元空间代码以降低维护成本。
  • 启用 C++ 14 语言功能,允许在 JDK C++ 源代码中使用C++ 14功能,并提供有关部分功能可用于 HotSpot VM 代码的特定指导。
  • 孵化器阶段的向量 API,其中 JDK 将安装一个孵化器模块,用于表示编译为支持的 CPU 体系结构上的最佳矢量硬件指令的矢量计算,以实现与等效标量计算更高的性能。
  • 将 JDK 移植到 Windows/AArch64 平台。随着新的服务器级和使用者 AArch64 (ARM64) 硬件的发布,Windows/AArch64 已成为一个重要的平台。
  • 在 x64 和 AArch64 体系结构上,将 JDK 移植到 Alpine Linux 和其他使用 musl 作为主 C 库的 Linux 发行版。Musl 是 ISO C 和 Posix 标准中描述的标准库功能的 Linux 实现。由于云部署、微服务和容器环境,Alpine Linux 由于其映像大小较小,因此被广泛采用。
  • 为不可变数据提供充当透明载体的记录类。
  • 增加 Unix 域套接字通道,其中 Unix 域 (AF_UNIX) 套接字支持添加到 nio.channels 包中的套接字通道和服务器套接字通道 API 中。该计划还扩展了继承的通道机制,以支持 Unix 域套接字通道和服务器套接字通道。Unix 域套接字用于同一主机上的进程间通信。它们在很多方面与 TCP/IP 套接字类似,只是它们由文件系统路径名称而不是 IP 地址和端口号寻址。新功能的目标是支持 Unix 域套接字通道的所有功能,这些功能在主要 Unix 平台和 Windows 中很常见。
  • 一种外部存储器访问 API,允许 Java 程序安全地访问 Java 堆以外的外部存储器。这一功能将在 JDK 16 中重新孵化。优化的目标包括提供单个 API 以对各种外部存储器(包括本机、持久和托管堆内存)进行操作,API 不应破坏 JVM 的安全性。此外,许多 Java 程序应访问外部存储器,如Lgnite、Memcached 和 MapDB。但是 JavaAPI 不能提供令人满意的访问外部内存 .MemorySegmentMemoryAddresses 的解决方案。
  • 用于运算符的模式匹配(该功能也在 JDK 14/15 版本中实现了预览)。在 JDK 16 上,模式匹配允许程序中的通用逻辑,即从对象中提取组件,可以更简洁、更安全地表达.instanceof 运算符
  • 提供用于打包独立的 Java应用程序 jpackage 工具。最初作为 JDK 14 中的孵化工具,jpackage在 JDK 15中仍然处于孵化期。预计到 JDK 16 版本,jpackage 将会进入生产环境中,支持本地包格式,并为用户提供流畅的安装体验,以及允许在打包时指定启动时间参数。格式包括 Windows 上的 msi 和 exe、 MacOs 上的 pkg 和 dmg、以及 Linux 上的 deb 和 rpm 。该工具可以直接从命令行调用,也可以以编程方式调用。新的打包工具解决了许多 Java 应用程序需要以一流的方式安装在本机平台上,而不是放置在类路径或模块路径上等问题。
  • OpenJDK 源代码存储库从 Mercurial 迁移到 Git。推动这项工作是借助版本控制系统元数据和可用工具及托管方面的优势。
  • 借助 JEP 369,托管平台迁移到 GitHub。在今年 9 月 5 日,Mercurial JDK 和 JDK 沙盒向 Git、GitHub 和 Skara 的过渡工作已实现。

继 Java 16 之后,Java 17 将于 2021 年 9 月发布,这是长期支持(LTS)版本,因此身处研发前线的开发者可以再等等。对此,你期待新版 Java 的到来吗?

参考链接:https://www.infoworld.com/art...
查看原文

赞 0 收藏 0 评论 0

技术宅小白 发布了文章 · 1月5日

Java 泛型 T,E,K,V,?,傻傻分不清?

前言

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

泛型带来的好处

在没有泛型的情况的下,通过对类型 Object 的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是本身就是一个安全隐患。

那么泛型的好处就是在编译的时候能够检查类型安全,并且所有的强制转换都是自动和隐式的。

public class GlmapperGeneric<T> {
  private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }
  
    public static void main(String[] args) {
        // do nothing
    }

  /**
    * 不指定类型
    */
  public void noSpecifyType(){
    GlmapperGeneric glmapperGeneric = new GlmapperGeneric();
    glmapperGeneric.set("test");
    // 需要强制类型转换
    String test = (String) glmapperGeneric.get();
    System.out.println(test);
  }

  /**
    * 指定类型
    */
  public void specifyType(){
    GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric();
    glmapperGeneric.set("test");
    // 不需要强制类型转换
    String test = glmapperGeneric.get();
    System.out.println(test);
  }
}

上面这段代码中的 specifyType 方法中 省去了强制转换,可以在编译时候检查类型安全,可以用在类,方法,接口上。

泛型中通配符

我们在定义泛型类,泛型方法,泛型接口的时候经常会碰见很多不同的通配符,比如 T,E,K,V 等等,这些通配符又都是什么意思呢?

常用的 T,E,K,V,?

本质上这些个都是通配符,没啥区别,只不过是编码时的一种约定俗成的东西。比如上述代码中的 T ,我们可以换成 A-Z 之间的任何一个 字母都可以,并不会影响程序的正常运行,但是如果换成其他的字母代替 T ,在可读性上可能会弱一些。通常情况下,T,E,K,V,?是这样约定的:

  • ?表示不确定的 java 类型
  • T (type) 表示具体的一个java类型
  • K V (key value) 分别代表java键值中的Key Value
  • E (element) 代表Element

    ?无界通配符

先从一个小例子看起 。

我有一个父类 Animal 和几个子类,如狗、猫等,现在我需要一个动物的列表,我的第一个想法是像这样的:

List<Animal> listAnimals

但是老板的想法确实这样的:

List<? extends Animal> listAnimals

为什么要使用通配符而不是简单的泛型呢?通配符其实在声明局部变量时是没有什么意义的,但是当你为一个方法声明一个参数时,它是非常重要的。

static int countLegs (List<? extends Animal > animals ) {
    int retVal = 0;
    for ( Animal animal : animals )
    {
        retVal += animal.countLegs();
    }
    return retVal;
}

static int countLegs1 (List< Animal > animals ){
    int retVal = 0;
    for ( Animal animal : animals )
    {
        retVal += animal.countLegs();
    }
    return retVal;
}

public static void main(String[] args) {
    List<Dog> dogs = new ArrayList<>();
  // 不会报错
    countLegs( dogs );
 // 报错
    countLegs1(dogs);
}

当调用 countLegs1 时,就会飘红,提示的错误信息如下:

图片

所以,对于不确定或者不关心实际要操作的类型,可以使用无限制通配符(尖括号里一个问号,即 <?> ),表示可以持有任何类型。像 countLegs 方法中,限定了上届,但是不关心具体类型是什么,所以对于传入的 Animal 的所有子类都可以支持,并且不会报错。而 countLegs1 就不行。

上界通配符 < ? extends E>

上界:用 extends 关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类。

在类型参数中使用 extends 表示这个泛型中的参数必须是 E 或者 E 的子类,这样有两个好处:

  • 如果传入的类型不是 E 或者 E 的子类,编译不成功
  • 泛型中可以使用 E 的方法,要不然还得强转成 E 才能使用
private <K extends A, E extends B> E test(K arg1, E arg2){
    E result = arg2;
    arg2.compareTo(arg1);
    //.....
    return result;
}
类型参数列表中如果有多个类型参数上限,用逗号分开

下界通配符 < ? super E>

下界: 用 super 进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object

在类型参数中使用 super 表示这个泛型中的参数必须是 E 或者 E 的父类。

private <T> void test(List<? super T> dst, List<T> src){
    for (T t : src) {
        dst.add(t);
    }
}

public static void main(String[] args) {
    List<Dog> dogs = new ArrayList<>();
    List<Animal> animals = new ArrayList<>();
    new Test3().test(animals,dogs);
}
// Dog 是 Animal 的子类
class Dog extends Animal {

}

dst 类型 “大于等于” src 的类型,这里的“大于等于”是指 dst 表示的范围比 src 要大,因此装得下 dst 的容器也就能装 src 。

?和 T 的区别

图片

?和 T 都表示不确定的类型,区别在于我们可以对 T 进行操作,但是对 ?不行,比如如下这种 :

// 可以
T t = operate();
// 不可以
?car = operate();

简单总结下:

T 是一个 确定的 类型,通常用于泛型类和泛型方法的定义,?是一个 不确定 的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法。

区别1:通过 T 来 确保 泛型参数的一致性

// 通过 T 来 确保 泛型参数的一致性
public <T extends Number> void
test(List<T> dest, List<T> src)

//通配符是 不确定的,所以这个方法不能保证两个 List 具有相同的元素类型
public void
test(List<? extends Number> dest, List<? extends Number> src)

像下面的代码中,约定的 T 是 Number 的子类才可以,但是申明时是用的 String ,所以就会飘红报错。

图片

不能保证两个 List 具有相同的元素类型的情况

GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric<>();
List<String> dest = new ArrayList<>();
List<Number> src = new ArrayList<>();
glmapperGeneric.testNon(dest,src);

上面的代码在编译器并不会报错,但是当进入到 testNon 方法内部操作时(比如赋值),对于 dest 和 src 而言,就还是需要进行类型转换。

区别2:类型参数可以多重限定而通配符不行

图片

使用 & 符号设定多重边界(Multi Bounds),指定泛型类型 T 必须是 MultiLimitInterfaceA 和 MultiLimitInterfaceB 的共有子类型,此时变量 t 就具有了所有限定的方法和属性。对于通配符来说,因为它不是一个确定的类型,所以不能进行多重限定。

区别3:通配符可以使用超类限定而类型参数不行

类型参数 T 只具有 一种 类型限定方式:

T extends A

但是通配符 ? 可以进行 两种限定:
? extends A

? super A

Class<T> 和 Class<?> 区别

前面介绍了 ?和 T 的区别,那么对于,Class<T> 和 <Class<?> 又有什么区别呢?Class<T> 和 Class<?>

最常见的是在反射场景下的使用,这里以用一段发射的代码来说明下。

// 通过反射的方式生成  multiLimit 
// 对象,这里比较明显的是,我们需要使用强制类型转换
MultiLimit multiLimit = (MultiLimit)
Class.forName("com.glmapper.bridge.boot.generic.MultiLimit").newInstance();

对于上述代码,在运行期,如果反射的类型不是 MultiLimit 类,那么一定会报
java.lang.ClassCastException 错误。

对于这种情况,则可以使用下面的代码来代替,使得在在编译期就能直接 检查到类型的问题:
图片

Class<T> 在实例化的时候,T 要替换成具体类。Class<?> 它是个通配泛型,? 可以代表任何类型,所以主要用于声明时的限制情况。比如,我们可以这样做申明:

// 可以
public Class<?> clazz;
// 不可以,因为 T 需要指定类型
public Class<T> clazzT;

所以当不知道定声明什么类型的 Class 的时候可以定义一 个Class<?>。

图片

那如果也想 public Class<T> clazzT; 这样的话,就必须让当前的类也指定 T ,

public class Test3<T> {
    public Class<?> clazz;
    // 不会报错
    public Class<T> clazzT;

小结

本文零碎整理了下 JAVA 泛型中的一些点,不是很全,仅供参考

查看原文

赞 0 收藏 0 评论 0

技术宅小白 发布了文章 · 1月5日

Session的销毁方式到底有哪些?

Session,作为我们离不开的后台的技术,它的出现主要是为了解决 Http 协议的无状态特点,用于解决用户状态的存储问题,而往往对于存储来说都会涉及到一个时间问题,下面我们来看看它的销毁方式到底有哪些。

销毁的方式

  • 默认时间到期
  • 自己设定到期时间
  • 立刻失效
  • 关闭浏览器
  • 关闭服务器

案例实操

默认时间到期

当客户端第一次请求 servlet 并且操作 session 时,session 对象生成,以 Tomcat 为例,Tomcat 中 session 默认的存活时间为 30min,即你不操作界面的时间,一旦有操作,session 会重新计时。那么 session 的默认时间可以改么?答案是肯定的。可以在 Tomcat 中的 web.xml 文件中进行修改。如下图:

自己设定到期时间

当然除了以上的修改方式外,我们也可以在程序中自己设定 session 的生命周期,通过 session.setMaxInactiveInterval(int); 来设定 session 的最大不活动时间,单位为秒。

HttpSession session = req.getSession();
session.setMaxInactiveInterval(5);

当然我们也可以通过 getMaxInactiveInterval(); 方法来查看当前 Session 对象的最大不活动时间。

立刻失效

或者我们也可以通过 session.invalidate(); 方法让 session 立刻失效。

session.invalidate();

关闭浏览器

session 的底层依赖 cookie 实现,因为不同用户访问服务器要判别到底是使用哪个 session,所以当用户第一次访问服务器的时候往往会把一个 session id 通过 cookie 存储到用户端,并且该 cookie 的有效时间为关闭浏览器,从而 session 在浏览器关闭时也相当于失效了(因为没有 session id 再与之对应)。如下图,关闭后再打开,重新给浏览器分配了个 session id。

image-20200708195027943

需要注意的是这里只是 cookie 失效了,你再访问相当于服务器把你当成了新用户,又给你创建了一个 session,并没有把之前的 session 对象销毁。

关闭服务器

当非正常关闭服务器时,session 销毁;当正常关闭服务器时,session 将被序列化到磁盘上,在工作空间 work 目录下的 SESSION.ser 文件中,如果对象被保存在了 session 中,服务器在关闭时要把对象序列化到硬盘,这个对象就必须实现 Serializable 接口,下次启动服务时,自动加载到内存。如下图,正常关闭后可以看到文件夹中多了一个 SESSIONS.ser 文件,再次启动服务器则文件消失。

扩展~Cookie的销毁

从图中除了看到 Cookie 的名称和内容外,我们还需要关心一个信息,到期时间,到期时间用来指定该 cookie 何时失效。默认为当前浏览器关闭即失效。我们可以手动设定 cookie 的有效时间(通过到期时间计算),通过 setMaxAge(int expiry); 方法设定 cookie 的最大有效时间,以为单位。

  • 大于 0 的整数,表示存储的秒数;若为负数,则表示不存储该 cookie;若为 0,则删除该 cookie。
  • 负整数:cookie 的 maxAge 属性的默认值就是 -1,表示只在浏览器内存中存活,一旦关闭浏览器窗口,那么 cookie 就会消失。
  • 正整数:表示 cookie 对象可存活指定的秒数。当生命大于 0 时,浏览器会把 Cookie 保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie 也会存活相应的时间。
  • :cookie 生命等于 0 是一个特殊的值,它表示 cookie 被作废!也就是说,如果原来浏览器已经保存了这个 Cookie,那么可以通过 Cookie 的 setMaxAge(0) 来删除这个 Cookie。 无论是在浏览器内存中,还是在客户端硬盘上都会删除这个 Co
查看原文

赞 0 收藏 0 评论 0

技术宅小白 发布了文章 · 2020-12-30

那些总是写“烂代码”的同学,强烈推荐你用这款 IDEA 插件!

1、目标


  idea集成sonar的代码检查,实现可以在提交代码前就检查你的代码,而不是将代码提交之后,之后再去检查。

  Sonar可以从以下七个维度检测代码质量,而作为开发人员至少需要处理前5种代码质量问题

1、不遵循代码标准 sonar可以通过PMD,CheckStyle,Findbugs等等代码规则检测工具规范代码编写

2、潜在的缺陷 sonar可以通过PMD,CheckStyle,Findbugs等等代码规则检测工具检测出潜在的缺陷

3、糟糕的复杂度分布 文件、类、方法等,如果复杂度过高将难以改变,这会使得开发人员难以理解它们 且如果没有自动化的单元测试,对于程序中的任何组件的改变都将可能导致需要全面的回归测试

4、重复 显然程序中包含大量复制粘贴的代码是质量低下的,sonar可以展示源码中重复严重的地方

5、注释不足或者过多 没有注释将使代码可读性变差,特别是当不可避免地出现人员变动时,程序的可读性将大幅下降 而过多的注释又会使得开发人员将精力过多地花费在阅读注释上,亦违背初衷

6、缺乏单元测试 sonar可以很方便地统计并展示单元测试覆盖率

7、糟糕的设计 通过sonar可以找出循环,展示包与包、类与类之间相互依赖关系,可以检测自定义的架构规则 通过sonar可以管理第三方的jar包,可以利用LCOM4检测单个任务规则的应用情况, 检测耦合。

2、前提


  • 已经搭建了sonarqube
  • jdk8环境(我的是jdk7,运行也没问题)

3、安装插件


设置——>Plugins中查找sonarLint插件,并安装。 安装完成后,要重启IDEA 。
在这里插入图片描述

4、配置项目

1)配置服务器
  我这里是编辑形式打开的弹窗,第一次添加时,是需要自己添加自己使用的sonar平台地址,一般是公司内部搭建的地址
在这里插入图片描述
在这里插入图片描述
2)选择项目

  上面配置好服务器的信息之后,就会获取到相应项目的信息,如下:
在这里插入图片描述
  配置完成后,在当前项目环境下,idea的左下角就可以看到sonar扩展了:
在这里插入图片描述

5、运行


在这里插入图片描述

以上仅为个人经验,如有错误或未考虑完全的地方,望不吝赐教。

查看原文

赞 0 收藏 0 评论 0

技术宅小白 发布了文章 · 2020-12-30

撸代码速度提升10倍的技巧,收藏慢慢看!!!

今天带大家提升一下写代码的速度,idea 是我们用的最多的开发工具,这个工具有个特别的牛逼的功能:live template。
这个功能掌握之后,撸代码的速度至少翻两番。
先带大家见识一下这玩意的威力。
idea 中随便创建一个类,比如创建一个 LiveTemplate.java,如下:
在这里插入图片描述

在光标的位置输入:psvm,然后按 Tab 或者 enter 键,神奇的效果出现了,main 方法瞬间出现了。
图片

这就是 idea 中 live template 的功能,俗称模板功能,可以将一段代码创建为一个模板,然后给这个模板定义个比较短的名字,然后在代码中输入模板的名字结合 tab 或者 enter 键,可以瞬间将模板代码片段引入到当前代码中,大大的提升了开发效率。
先来看一些常用的模板,这些大家都花点时间记住。
1、常用的 live tempalte

1.1、ifn

if (args == null) {

}

1.2、psvm

public static void main(String[] args) {

}

1.3、fori

for (int i = 0; i < ; i++) {

}

1.4、inn

if (args != null) {

}

1.5、inst

if (args instanceof Object) {
    Object o = (Object) args;
}

1.6、toar

List<String> list = new ArrayList<>();

然后按toar,出现下面结果

List<String> list = new ArrayList<>();
String[] strings = list.toArray(new String[list.size()]);

1.7、prsf

private static final

1.8、psf

public static final

1.9、psfi

public static final int

1.10、psfs

public static final String

1.11、thr

throw new

2、更多 live tempalte
上面介绍的都是 java 的一些,实际上还有很多,比如安卓的、sql 的、html 的,都有,大家可以自己去看一下

File->Settings->live tempalte

图片

3、自定义 live template
idea 中自带了一些常用的,但是有时候我们也想自定义一些自己比较常用的模板,那么怎么操作呢?
3.1、File->Settings->Live template
在这里插入图片描述

3.2、添加一个分组
如下图点击"+",选择"Template Group",组名我们就叫 my 吧,可以随意起名
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3、添加 Live templates
在我们 my 组下面添加一个模板,操作如下
图片

3.4、设置模板信息
图片

  • Abbreviation(缩进名):即之后代码输入 pssd 按快捷键即可生成 private static String var
  • Edit variables(编辑编写):编辑变量,包括顺序,变量功能等,详见下方备注
  • Description(注释):注释模板功能
  • Template text(模板主体):x x 为变量,END 为自带变量,即最后光标停留位置
  • Applicable(应用范围):指明在什么文件什么情况下使用。一般默认勾选 java 就可以
  • options(快捷键):即输入 pssd 后按下 Enter 还是 Tab 生成模板。作者一般使用 Tab 键,一方面是防止与自带模板冲突,另一方面与 shell 快捷键一至
  • Reformate According to Style:自动进行代码格式化。不勾选代码不会自动缩进换行

VAR1,VAR2 并不代表输入顺序,变量输入顺序在 Edit variables 中,通过调整上下顺序改变,高级变量的使用可参考下一节,或参考官方文档

https://www.jetbrains.com/hel...

3.5、比如我们定义一个 try-catch-finnaly 的快捷键
图片

然后在代码中输入"tcf+tab 键",瞬间出现下面代码,是不是特别的爽

try {

} catch (Exception e) {

} finally {

}
查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 2 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2020-12-21
个人主页被 960 人浏览