Posted in Working Skills, 技术

Angular JS 生成动态二维码

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!
“小步快跑,试错迭代” – 《腾讯传》

一、场景

二维码的场景,很多。这里是二维码一种小场景,比如分享一个链接,商品链接,项目链接,优惠券链接…
技术实现,如果用后端实现,需要构造输出一个图片流。或者后端生产二维码图片,给图片地址就好了。弊端,这个二维码就是一个链接,后端的文件 IO 操作,还得考虑存储。太费力。
如果前端实现,这样就很轻松了。这只是个分享二维码,分享出去给人家扫一扫。利用前端的 canvas,这里坐下调研。
jq 封装的 qrcode.js ,文章网上一大堆。
angular js :https://github.com/monospaced/angular-qrcode

二、使用

1.安装 angular-qrcode

git clone https://github.com/monospaced/angular-qrcode.git
cd angular-qrcode
npm install

2.引入 js 文件

<script src="/node_modules/qrcode-generator/js/qrcode.js"></script>
<script src="/node_modules/qrcode-generator/js/qrcode_UTF8.js"></script>
<script src="/node_modules/angular-qrcode/angular-qrcode.js"></script>

并在你 angular 配置中加入对这个模块的依赖:

angular
.module('your-module', [
'monospaced.qrcode',
]);

 

3.使用

在线案例:monospaced.github.io/angular-qrcode

使用元素:

<qrcode data="string"></qrcode>

具体配置参数:

<qrcode data="string" version="2" error-correction-level="Q" size="200" color="#fff" ba kground="#000"></qrcode>

 

作为可下载的图片:

<qrcode data="string" download></qrcode>

 

作为有链接的二维码:

<qrcode data="http://example.com" href="http://example.com"></qrcode>

 

download 和 href 互斥,不能同时使用。具体参数入下:

<qrcode version="{{version}}" error-correction-level="{{level}}" size="{{size}}" data="{{var}}" href="{{var}}" color="{{color}}" background="{{background}}" download></qrcode>

 

三、小结

二维码是个好东西。

推荐:《 Springboot 系列

欢迎扫一扫我的公众号关注 — 及时得到博客订阅哦!
— http://www.bysocket.com/ —
— https://github.com/JeffLi1993 —

Posted in Spring, Spring Boot, 技术

Springboot 实现 Restful 服务,基于 HTTP / JSON 传输

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!
“怎样的人生才是没有遗憾的人生?我的体会是:
(1)拥有健康;
(2)创造“难忘时刻”;
(3)尽力做好自己,不必改变世界;
(4)活在当下。”
– 《向死而生》李开复
Spring Boot 系列文章:《Spring Boot 那些事
基于上一篇《Springboot 整合 Mybatis 的完整 Web 案例》,这边我们着重在 控制层 讲讲。讲讲如何在 Springboot 实现 Restful 服务,基于 HTTP / JSON 传输。

一、运行 springboot-restful 工程

git clone 下载工程 springboot-learning-example ,项目地址见 GitHub – https://github.com/JeffLi1993/springboot-learning-example。下面开始运行工程步骤(Quick Start):

 

1.数据库准备
a.创建数据库 springbootdb:
CREATE DATABASE springbootdb;
b.创建表 city :(因为我喜欢徒步)
DROP TABLE IF EXISTS  `city`;
CREATE TABLE `city` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '城市编号',
  `province_id` int(10) unsigned  NOT NULL COMMENT '省份编号',
  `city_name` varchar(25) DEFAULT NULL COMMENT '城市名称',
  `description` varchar(25) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
c.插入数据
INSERT city VALUES (1 ,1,'温岭市','BYSocket 的家在温岭。');

 

2. springboot-restful 工程项目结构介绍
springboot-restful 工程项目结构如下图所示:
org.spring.springboot.controller – Controller 层
org.spring.springboot.dao – 数据操作层 DAO
org.spring.springboot.domain – 实体类
org.spring.springboot.service – 业务逻辑层
Application – 应用启动类
application.properties – 应用配置文件,应用启动会自动读取配置

 

3.改数据库配置
打开 application.properties 文件, 修改相应的数据源配置,比如数据源地址、账号、密码等。(如果不是用 MySQL,自行添加连接驱动 pom,然后修改驱动名配置。)

 

4.编译工程
在项目根目录 springboot-learning-example,运行 maven 指令:
mvn clean install

 

5.运行工程
右键运行 springboot-restful 工程 Application 应用启动类的 main 函数。
用 postman 工具可以如下操作,
根据 ID,获取城市信息
GET http://127.0.0.1:8080/api/city/1
获取城市列表
GET http://127.0.0.1:8080/api/city
新增城市信息
POST http://127.0.0.1:8080/api/city
更新城市信息
PUT http://127.0.0.1:8080/api/city
删除城市信息
DELETE http://127.0.0.1:8080/api/city/2

 

二、springboot-restful 工程控制层实现详解

1.什么是 REST?
REST 是属于 WEB 自身的一种架构风格,是在 HTTP 1.1 规范下实现的。Representational State Transfer 全称翻译为表现层状态转化。Resource:资源。比如 newsfeed;Representational:表现形式,比如用JSON,富文本等;State Transfer:状态变化。通过HTTP 动作实现。
理解 REST ,要明白五个关键要素:
资源(Resource)
资源的表述(Representation)
状态转移(State Transfer)
统一接口(Uniform Interface)
超文本驱动(Hypertext Driven)

 

6 个主要特性:
面向资源(Resource Oriented)
可寻址(Addressability)
连通性(Connectedness)
无状态(Statelessness)
统一接口(Uniform Interface)
超文本驱动(Hypertext Driven)

 

2.Spring 对 REST 支持实现
CityRestController.java 城市 Controller 实现 Restful HTTP 服务
public class CityRestController {

    @Autowired
    private CityService cityService;

    @RequestMapping(value = "/api/city/{id}", method = RequestMethod.GET)
    public City findOneCity(@PathVariable("id") Long id) {
        return cityService.findCityById(id);
    }

    @RequestMapping(value = "/api/city", method = RequestMethod.GET)
    public List<City> findAllCity() {
        return cityService.findAllCity();
    }

    @RequestMapping(value = "/api/city", method = RequestMethod.POST)
    public void createCity(@RequestBody City city) {
        cityService.saveCity(city);
    }

    @RequestMapping(value = "/api/city", method = RequestMethod.PUT)
    public void modifyCity(@RequestBody City city) {
        cityService.updateCity(city);
    }

    @RequestMapping(value = "/api/city/{id}", method = RequestMethod.DELETE)
    public void modifyCity(@PathVariable("id") Long id) {
        cityService.deleteCity(id);
    }
}

 

代码详解:
@RequestMapping 处理请求地址映射。
method – 指定请求的方法类型:POST/GET/DELETE/PUT 等
value – 指定实际的请求地址
consumes – 指定处理请求的提交内容类型,例如 Content-Type 头部设置application/json, text/html
produces – 指定返回的内容类型
@PathVariable URL 映射时,用于绑定请求参数到方法参数
@RequestBody 这里注解用于读取请求体 boy 的数据,通过 HttpMessageConverter 解析绑定到对象中

 

3.HTTP 知识补充
GET            请求获取Request-URI所标识的资源
POST          在Request-URI所标识的资源后附加新的数据
HEAD         请求获取由Request-URI所标识的资源的响应消息报头
PUT            请求服务器存储一个资源,并用Request-URI作为其标识
DELETE       请求服务器删除Request-URI所标识的资源
TRACE        请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT  保留将来使用
OPTIONS   请求查询服务器的性能,或者查询与资源相关的选项和需求

 

三、小结

Springboot 实现 Restful 服务,基于 HTTP / JSON 传输,适用于前后端分离。这只是个小demo,没有加入bean validation这种校验。还有各种业务场景。
欢迎扫一扫我的公众号关注 — 及时得到博客订阅哦!
— http://www.bysocket.com/ —
— https://github.com/JeffLi1993 —
Posted in 思考

死亡学分一起修吧

听着赵雷的《理想》,写写看完《向死而生》的摘记与思考,就这样《活着活着就老了》。
【死亡学分篇】书中说:“人在面对疾病、死亡、悲伤等重大失落时,会产生“五个阶段”的心理反应─否认、愤怒、讨价还价、沮丧和接受。”
一般人想着能长生不老就好,往往面对死亡、疾病会更加深有体会。但却在努力为了钱,不开心压抑着活着的努力,渴望有些回报。往往回报不大,还要为讨价还价操劳过度。身体小事,都是大事。注意休息,注意心理生理健康。


书中说:“怎样的人生才是没有遗憾的人生?我的体会是:(1)拥有健康;(2)创造“难忘时刻”;(3)尽力做好自己,不必改变世界;(4)活在当下。”
第一点,爱运动不是第一,饮食作息才是通病。吃点素的,早点关机睡觉。第二点,放下面子脸皮,厚脸皮是好事。第三点,做自己,也要听去别人爸妈建议。但听心声,总错不了。

第四点,废话咯。乔布斯曾说过:“记住你即将死去。”


【人生规划篇】书中说:“我一直笃信“付出总有回报”,出差的时候吩咐秘书尽量选夜间航班,下了飞机可以立即洽谈公事。”
想起友人tam说过的:我也相信努力,相信努力总比不努力好我相信命的意思是,我相信 有些东西不是努力可以解决的

甚至不是你可以解决的

困难在于,你无法知道哪些东西努力可以解决,哪些不可以

所以,为了不错过那些努力可以解决的东西,你最好还是努力点


书中说:“做自己感兴趣的工作是最重要的。”
人生规划,免不了职业。职业和事业的区别就不说了。如果在职业中,一定要保持小小的事业心。你努力职业中获取,股权期权分红等,慢慢的升职成为了事业。所以当不了老板,低风险低收益的保持事业心的干事,会有属于你的舞台。


书中说:“不要因为年轻,只顾事业而忘了家庭”
这是真的,你现在有个家。你结婚了有了新家。你老了你儿子有了个家。你在上一个家,到下一个家,不要忘记家。他们理解你,他们也需要你。他们不需要你多少时间全部的关心,但他们需要重视。所以抽10分钟,认真视频,认真电话。回到家陪他们下厨,聊天吃饭,放下手机吧。


书中说:“饮食、运动、睡眠、减压,结果就是好吃、好玩、好睡、好轻松。”
这是生活,说白了就是心态。自私点,对自己好点。

最后

你若盛开,蝴蝶自来;你若精彩,天自安排。

最好的赞赏

就是你的关注

Posted in Spring, Spring Boot, 技术

Springboot 整合 Mybatis 的完整 Web 案例

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!
推荐一本书《腾讯传》。
Spring Boot 系列文章:《Spring Boot 那些事
新年第一篇 Springboot 技术文诞生。泥瓦匠准备写写 Springboot 相关最佳实践。一方面总结下一些 Springboot 相关,一方面和大家交流交流 Springboot 框架。
现在业界互联网流行的数据操作层框架 Mybatis,下面详解下 Springboot 如何整合 Mybatis ,这边没有使用 Mybatis Annotation 这种,是使用 xml 配置 SQL。因为我觉得 SQL 和业务代码应该隔离,方便和 DBA 校对 SQL。二者 XML 对较长的 SQL 比较清晰。

一、运行 springboot-mybatis 工程

git clone 下载工程 springboot-learning-example ,项目地址见 GitHub。下面开始运行工程步骤(Quick Start):
1.数据库准备
a.创建数据库 springbootdb:
CREATE DATABASE springbootdb;
b.创建表 city :(因为我喜欢徒步)
DROP TABLE IF EXISTS  `city`;
CREATE TABLE `city` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '城市编号',
  `province_id` int(10) unsigned  NOT NULL COMMENT '省份编号',
  `city_name` varchar(25) DEFAULT NULL COMMENT '城市名称',
  `description` varchar(25) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
c.插入数据
INSERT city VALUES (1 ,1,'温岭市','BYSocket 的家在温岭。');
2. 项目结构介绍
项目结构如下图所示:
org.spring.springboot.controller – Controller 层
org.spring.springboot.dao – 数据操作层 DAO
org.spring.springboot.domain – 实体类
org.spring.springboot.service – 业务逻辑层
Application – 应用启动类
application.properties – 应用配置文件,应用启动会自动读取配置
3.改数据库配置
打开 application.properties 文件, 修改相应的数据源配置,比如数据源地址、账号、密码等。(如果不是用 MySQL,自行添加连接驱动 pom,然后修改驱动名配置。)
4.编译工程
在项目根目录 springboot-learning-example,运行 maven 指令:
mvn clean install
5.运行工程

右键运行 Application 应用启动类的 main 函数,然后在浏览器访问:

http://localhost:8080/api/city?cityName=温岭市
可以看到返回的 JSON 结果:
{
    "id": 1,
    "provinceId": 1,
    "cityName": "温岭市",
    "description": "我的家在温岭。"
}
如图:

二、springboot-mybatis 工程配置详解

1.pom 添加 Mybatis 依赖
<!-- Spring Boot Mybatis 依赖 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>${mybatis-spring-boot}</version>
</dependency>
mybatis-spring-boot-starter 工程依赖如图:
整个工程的 pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>springboot</groupId>
    <artifactId>springboot-mybatis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-mybatis :: 整合 Mybatis Demo</name>

    <!-- Spring Boot 启动父依赖 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.1.RELEASE</version>
    </parent>

    <properties>
        <mybatis-spring-boot>1.2.0</mybatis-spring-boot>
        <mysql-connector>5.1.39</mysql-connector>
    </properties>

    <dependencies>

        <!-- Spring Boot Web 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring Boot Test 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Spring Boot Mybatis 依赖 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis-spring-boot}</version>
        </dependency>

        <!-- MySQL 连接驱动依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector}</version>
        </dependency>

        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>
2.在 application.properties 应用配置文件,增加 Mybatis 相关配置
## Mybatis 配置
mybatis.typeAliasesPackage=org.spring.springboot.domain
mybatis.mapperLocations=classpath:mapper/*.xml
mybatis.typeAliasesPackage 配置为 org.spring.springboot.domain,指向实体类包路径。mybatis.mapperLocations 配置为 classpath 路径下 mapper 包下,* 代表会扫描所有 xml 文件。
mybatis 其他配置相关详解如下:
mybatis.config = mybatis 配置文件名称
mybatis.mapperLocations = mapper xml 文件地址
mybatis.typeAliasesPackage = 实体类包路径
mybatis.typeHandlersPackage = type handlers 处理器包路径
mybatis.check-config-location = 检查 mybatis 配置是否存在,一般命名为 mybatis-config.xml
mybatis.executorType = 执行模式。默认是 SIMPLE
3.在 Application 应用启动类添加注解 MapperScan
Application.java 代码如下:
/**
 * Spring Boot 应用启动类
 *
 * Created by bysocket on 16/4/26.
 */
// Spring Boot 应用的标识
@SpringBootApplication
// mapper 接口类扫描包配置
@MapperScan("org.spring.springboot.dao")
public class Application {

    public static void main(String[] args) {
        // 程序启动入口
        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件
        SpringApplication.run(Application.class,args);
    }
}
mapper 接口类扫描包配置注解 MapperScan :用这个注解可以注册 Mybatis mapper 接口类。
4.添加相应的 City domain类、CityDao mapper接口类

City.java:

/**
 * 城市实体类
 *
 * Created by bysocket on 07/02/2017.
 */
public class City {

    /**
     * 城市编号
     */
    private Long id;

    /**
     * 省份编号
     */
    private Long provinceId;

    /**
     * 城市名称
     */
    private String cityName;

    /**
     * 描述
     */
    private String description;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getProvinceId() {
        return provinceId;
    }

    public void setProvinceId(Long provinceId) {
        this.provinceId = provinceId;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
CityDao.java:
/**
 * 城市 DAO 接口类
 *
 * Created by bysocket on 07/02/2017.
 */
public interface CityDao {

    /**
     * 根据城市名称,查询城市信息
     *
     * @param cityName 城市名
     */
    City findByName(@Param("cityName") String cityName);
}
其他不明白的,可以 git clone 下载工程 springboot-learning-example ,工程代码注解很详细。 https://github.com/JeffLi1993/springboot-learning-example

三、其他

利用 Mybatis-generator自动生成代码 http://www.cnblogs.com/yjmyzz/p/4210554.html
Mybatis 通用 Mapper3 https://github.com/abel533/Mapper
Mybatis 分页插件 PageHelper https://github.com/pagehelper/Mybatis-PageHelper
最后,推荐阅读:《 Spring Boot 之 HelloWorld 详解
欢迎扫一扫我的公众号关注 — 及时得到博客订阅哦!
— http://www.bysocket.com/ —
— https://github.com/JeffLi1993 —
Posted in 技术

【阅后有感】《程序员必读的职业生涯规划书》

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!

“记住你即将死去”

浮动的时代,躁动的我们。但在动车上看书,往往静的下来。就这样让时间静静的耗着,躺着在文字之间度过。再品 Easy 的《程序员必读的职业生涯规划书》,牛逼,非常牛逼,就是牛逼。我是在年前上班粗粗看过,武汉到杭州的路上我仔细翻阅了各章内容。尤其原理篇就吸引我了,不知道是不是因为刚好前面一段时间看过《Poor Dad Rich Dad》,里面的原理讲的是那么有点像。Easy 自己也在四画像中提到了罗伯特,将走向财务自由划为了四个维度。下面是我阅后有感的四个方面吧:

如何看待工作?


什么是工作?对于工作的解释,超级阿嬷讲的,最接地气:“如果不知道自己想干什么,就先工作。只要工作,就可以得到米、酱、酱油、朋友和信任。可以一边工作,一边寻找真正想干的事,千万不要游手好闲。” — 《超级阿嬷的信》

阿嬷的意思是,任何的工作都离不开人和钱。因此,职业和事业的不同就是。职业更在乎的是与谁一起工作,还有能挣多少钱。

第一是与人一起工作,领导、小领导、师兄和同事等。在工作中,你依旧是你,你的性格,你的能力会被领导看见…有些同事在与你相处下,渐渐成为了你的朋友。同样你会拥有了部分同事或者新朋友的信任。至少8个小时每天的工作,不得不说工作就是是生活必不可少的一部分。如果是你真正想干的事,往往这时间会更长,往往分不清工作与生活的边界。

第二是工作才能获得薪资。比较认可 Easy 说的,工作最重要的是累积金钱。是的,泥瓦匠曾在一度浪过,一度挥霍,一度允许自己犯错的日子里思考。我,但着实觉得穷怕了。金钱是现实世界用以维持生计的必须资源。所以多挣点钱没错,等有一天发现它有用的时候,一定用得上。

薪资和跳槽挂钩吗?一定挂钩,但容易走入误区的是跳槽不等于涨薪。跳槽只是解决了现在的很差,换了个更好的工作。比如,996 每天晚归的娃娃,可能拿着比如高出几K的薪资。往往算下工时的薪资,你恰恰比人家低了好多。而这样的你丧失了运动,即对健康这个资产的投资,往往日积月累的身体负债让你得不偿失。这句话是我看李开复《向死而生》得出的。往往失去过了才懂得珍惜,李开复也如此。他在书中和大师对话中,说到自己人生目标,以为自己自我认识完全。恰恰没,在没日没夜的工作中,他丧失了本真,追名逐利的日子里他光彩的背后付出更多。

我真的自我认识完全了吗?


李开复没有,我也没有。往往自我认识容易让我越陷越深。看《向死而生》,李开复他自己批判的自己。随波逐流,追逐自认为的“最大影响力”,现实社会带着他,陷入了追名逐利。同样,我不是批判李开复,他的价值,他向死而生,他在死亡擦过了边球。我欣赏他,欣赏那些向死而生的人。乔布斯说的,“记住你即将死去”。所以做一个简单的人,做一个充满正能量的人。因为负能量容易更负,坑越深就越爬不上来了。你我一直在处于自我认识完全的过程,这个过程不要去拒绝它,然后享受它。同样不能丢弃它,它就是梦想。就算不能实现,梦想终归是梦想。如果这个梦想没有实现,可以再树立下一个梦想。这样,人到死都能拥有众多的梦想。人生就是这样的反反复复。不进则退,机会留给一直学习的人。但学了不亏难道都是对吗?这是下面要说的话题。

自我认识,就是成长,成长来源思考,来源落地的行动。

学了不亏


学了不亏,这是个好的态度。但保持两点去做会让你更贴近现实。第一学了不亏是因为工作需要,业务能力学习,业务相关技能的学习让你更好的在这个岗位体现出你的价值。这样雇主和你的价值联系也紧密,你会得到相应的升职加薪以及会有一定的股份报酬赌注。

第二是你的兴趣,兴趣驱动的学习往往是不累,并不那么疲惫。并不那么疲惫,不代表学习没有曲线,每个学习都不会那么顺利。仿佛就是从解决问题,解决问题到一个稳定的软件一样。

很多人问题学这个好吗,学这个咋样?我就说学了不亏,因为这段时间去学某个东西,总比不抉择亏。学着学着就明白了哪个该学哪个不该。学着你就会学习放弃,同样学会对自己总结,学会分享总结。

乐于分享,初心不变,虚荣也罢


这个点我没做到以后说。书本文章地址:传送门

欢迎扫一扫我的公众号关注 — 及时得到博客订阅哦!
— http://www.bysocket.com/ —
— https://github.com/JeffLi1993 —

 

Posted in 思考

年计划,技术儿告诉你怎么做?

博主:BYSocket
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!
新年我的本命年,大家辛苦了。新年快乐,健健康康就好。

关于计划


谈年计划,总是计划赶不上变化。但不计划,像我这种健忘的,曾经会老是在想我该干嘛。所以好记性不如烂笔头,我该记得都记着。比如天计划:
回到年计划。很多人会列出年计划,自然很多人会失败。但往往一开始很多人会感觉胜券在手中一样。年计划相比天计划,只不过是时间长点罢了。因此年计划,是每天做的事情一个阶段性小结的结果。
切勿切勿,假大空。比如“升职加薪迎娶白富美当上CTO”…升多少、加多少是个头、自然白富美看脸蛋和技巧、CTO那就胡扯吧。因此,年计划不是梦想。年计划是未来3-5年愿景的一个年度目标。是一个具体的、可实现、有结果导向、有时间约束的目标。最好最好不要超过 3 件事,因为欲望无止境,可能你先做好一件事试试会更好。

关于怎么做年计划


第一、正式心态

计划其实是种对生活对工作的记录。比如周报产生自工作日报。计划并不会夺走你很多的时间,恰恰可以帮你在更好的时间找到做更好的事情。

第二、从 3 年 5 年 10 年找出今年要干的事情

比如 5 年后,我想成为一名作者。我觉得如果不误人子弟,恰恰这是最简单的事情,做快乐的事,并帮助社会与人。但,我今年不可能成为一名作者。因为我不想误人子弟,同样得考虑销量。
年计划呢?我就先写,从一名博主开始。零散的写了个把年,系列写的不多。所以今年的目标是写技术系列文章。

第三、具体实施呢

那就简单了。从 5 年分割到年,从年分割到周就行了。具体计划是每周产出 2 篇技术系列文章。另外我用着,换着感觉就 Evernote 在手,就行了。顺便说下,我是个 Listful 控。
简单,有效,一件事就够了。这就是年计划
Posted in Working Skills, 技术

【工作代码】复杂 JSON 值替换处理

总结下最近的工作遇到的点:
入参复杂 JSON 层层嵌套,Java 怎么优雅的处理。

一、关于 JSON

JSON 是类似 XML 用于存储和交互文本信息。但优于 XML ,其更小,更快,更易懂和解析。其是一个无序的”名称/值”对的集合。由

{ 左括号
"" 名称 String
:
值
} 右括号

组成。然后 名称值对 以逗号分隔。

二、场景描述

是一个正则匹配替换的操作。一个很长很复杂的 JSON 入参,通过正则匹配其 content 对应的值中的图片地址并替换。

三、思考

框架选型 – fastjson
(fastjson 是一个性能很好的 Java 语言实现的 JSON 解析器和生成器,来自阿里巴巴的工程师开发。)

a . 思路
Java 是面向对象的语言。我要利用 fastjson 把复杂的 JSON 写出其对应的 BO 对象,然后正则替换 content 内容(即 operatorContent 方法),然后重新生成 JSON 响应。即下面代码操作:

OperatorBO operatorBO = JSON.parseObject(jsonString, OperatorBO.class);
operatorBO.setContent(operatorContent(operatorBO.getContent()));
String newJsonString = JSON.toJSONString(operatorBO);

 

好处:代码易读,容易维护
坏处:BO 实在是太复杂,而且很多数组嵌数组。PHP -> Java 服务化过程中很多不可控,容易出 BUG。

涉及的API :
序列化对象到 JSON:

String jsonString = JSON.toJSONString(obj);

反序列化 JSON 到对象:

VO vo = JSON.parseObject("...", VO.class);
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!

b . 思路
只是替换操作,所以不用太考虑代码易读性。直接利用 fastjson 直接转出 JSONArray 对象,然后操作该对象即可。JSONArray 对象本质就是一个 List<Object> 如下代码:

public class JSONArray extends JSON {
    private final List<Object> list;
    protected transient Object relatedArray;
}

具体伪代码如下:

String jsonString = "[{" + "\"content\":\"content value 1\"" + "}]";
JSONArray itemDataJsonArr = JSON.parseArray(jsonString);
String content = itemDataJsonArr.getJSONObject(0).getString("content");
content = content + "23";
itemDataJsonArr.getJSONObject(0).put(CONTENT,content);

好处:不用关心其他复杂的键值对,目标只关注要替换的节点名称。
坏处:代码不易读,相对也还容易维护。

涉及的API :
替换对应的节点名称的值:

JSONObject.put("...",value);

反序列化 JSON 到 JSONArray 对象:

JSONArray jSONArray = JSON.parseObject("...");

思路 c d e …

 

四、小结

根据服务化场景,在不确定入参 JSON 的复杂度情况下,选择了思路 b.这篇其实是工作上的小小结。任何技术,任何框架的 API 是否好用优雅,是具体场景决定的。

如以上文章或链接对你有帮助的话,别忘了在文章结尾处评论哈~ 你也可以点击页面右边“分享”悬浮按钮哦,让更多的人阅读这篇文章。

Posted in Java, 技术

有趣的译文 《Java Pattern 那些小事》

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!

一、现代的玩具 – Java 可以做很多事

一个 Q 与 A 的对话,展示了 Java 那些小事。

Q : 5 是整数吗?

A : 是。


Q : -23 是数吗?

A : 是,但负数使用场景很少。


Q : 5.32 是整数吗?

A : 不是,我们不用这种数值类型表示 5.32 。


Q : 5 属于什么数值类型?

A : int (整型)。
批注: int 是基本类型,int 代表整数。


Q : 快,想出另一个整数!

A : 19?


Q : 那 true 属于什么数值类型?

A : boolean (布尔型)。


Q : false 属于什么数值类型?

A : boolean。


Q : 想得出其他布尔值吗?

A : 没有,布尔值只有 true 和 false。


Q : int 是什么?

A : 一种类型。


Q : boolean 是什么?

A : 另一种类型。


Q : 什么是类型?

A : 类型是一个相关值集合的名称。


Q : 能举例解释下类型吗?

A : 使用类型就像使用一种集合一样。比如使用 boolean 可以表示逻辑值:是与非


Q : 能创建新的类型吗?

A : 我们还不知道怎么创建。


Q : 画出下面类的基本关系。

abstract class Seasoning {}

class Salt extends Seasoning {}

class Pepper extends Seasoning {}

A : 这样画?
图 1.1 Seasoning 类关系图

wechatimg4


Q : 是的。Seasoning 是数据类型,Salt 和 Pepper 是 Seasoning 的具体类型。

A : 好的。三个都是新类型吗?


Q : 是的。那么 new Salt() 是一个 Seasoning 吗?

A : 是的。 new Salt() new 关键字表示创建了 Salt 的一个实例,每个 Salt 的实例也是 Seasoning。


Q : new Pepper() 也是吗?

A : 是的。它也是一个 Seasoning。 new Pepper() new 关键字表示创建了 Pepper 的一个实例,每个 Pepper 的实例也是 Seasoning。


Q : 什么是 abstract , class 和 extends 关键字?

A : 简单地说:
abstract class 表示抽象数据类型
class 表示具体类型
extends 连接了具体类型到数据类型


Q : 还有其他的 Seasoning 具体类型吗?

A : 没有,因为只有 Salt 和 Pepper 继承 Seasoning。


Q : 正确。只有 Salt 和 Pepper 是 Seasoning 的具体类型。我们见过类似 Seasoning 数据类型吗?

A : 没有。但是 boolean 类型有两个值:true 和 false。
批注:值与具体类型是不同的。


Q : 再定义一个 Seasoning 具体类型:

class Thyme extends Seasoning {}

A : 再来一个:

class Sage extends Seasoning {}

Q : 4 个 Seasoning 具体类型了。

A : 是的。


Q : 什么是笛卡尔点?

A : 是一对数字。


Q : 曼哈顿地点位于哪里?

A : 两个城市街道的十字路口。


Q : 看代码,CartesianPt 类和 ManhattanPt 类有啥不同于 Salt 类和 Pepper 类

abstract class Point {}
class CartesianPt extends Point {
    int x;
    int y;
    CartesianPt(int _x, int _y){
        x = _x;
        y = _y;
    }
}
class ManhattanPt extends Point {
    int x;
    int y;
    ManhattanPt(int _x, int _y){
        x = _x;
        y = _y;
    }

}

A : 两个类中 {} 包含了三个元素。x 和 y 是表示点的坐标,但是构造函数里面包含什么呢?(批注:构造函数是同类名的函数)


Q : CartesianPt 和 ManhattanPt 各自的构造函数里面包含各自的字段值。

A : 那怎么使用构造函数呢?


Q : new 关键字作用于构造函数,会创建一个新的该类型实例。

A : 这样子呀。


Q : 比如下面的代码:

new CartesianPt(2,3);

使用 CartesianPt 的构造函数,创建一个 CartesianPt 实例。

A : 这样创建的 CartesianPt 实例 ,其字段 x 值为 2,y 值为 3。

class CartesianPt extends Point {

还有 extends 关键字表示创建的 CartesianPt 也是 Point。


Q : 对。那么下面代码是创建一个 ManhattanPt 实例吗?

new ManhattanPt(2,3);

A : 是,它也有 x 值为 2,y 值为 3。


Q : 构造函数就这样?

A : 基本是了,但在没有定义过构造函数的代码里,以前用过构造函数。这是怎么实现的呢?


Q : 比如 Salt 和 Pepper 没有任何字段,但是它们有个默认构造函数。

A : 这是正确使用默认构造函数的方式吗?


Q : 是的。默认构造函数没有包含字段值。使用 new 关键字创建实例时,创建的实例没有字段值。

A : 好,下面这段代码呢?

new Point()

Q : Point 是一个抽象类,它是不完整的类,所以 new 关键字不能创建 Point 实例。

A : 这就说得通了,继续。


Q : 以下定义的类是另一种抽象数据类型和它的具体数据类型吗?

abstract class Num {}
class Zero extends Num {}
class OneMoreThan extends Num {
    Num predecessor;
    OneMoreThan (Num p) {
        predecessor = p;
    }
}

A : 是的。它们定义了一种抽象数据类型和两个具体数据类型。
图 1.2 Num 类关系图

wechatimg5


Q : new Zero() 是 Num 的实例吗?

A : 明显是的。就像 new Salt() 是 Salt 的一个实例。


Q : new OneMoreThan(new Zero()) 是 Num 的实例吗?

A : 是。OneMoreThan 继承了 Num,new OneMoreThan() 是一个 OneMoreThan 实例,本身也是一个 Num 实例,并包含了一个 Num 实例(这里是指new Zero())。


Q : 为什么 OneMoreThan 可以这样实现?

A : new Zero() 是一个 Num 实例,OneMoreThan 的实例创建时,包含了 Zero 的实例。


Q : 包含 Zero 实例?

A : OneMoreThan 的实例拥有一个值叫做 predecessor,即这个值可以是 new Zero()。


Q : predecessor 只能是 Zero 的实例?

A : 不是的。Num predecessor 说明了 predecessor 是一个 Num,所以具体表现为 OneMoreThan 或者 Zero 的实例。


Q : 那 new OneMoreThan(new OneMoreThan(new Zero()))呢?

A : 一个 Num 的实例,最外层的 new OneMoreThan 拥有了一个 Num 的实例:new OneMoreThan(new Zero())


Q : 那 new OneMoreThan(0)?

A : 胡说,0 不是一个 Num 。


Q : new Zero() 和 0 一样吗?

A : 不一样,虽然 new Zero() 和 0 概念相似,但不一样。


Q : new OneMoreThan(new Zero()) 和 1 概念相似?

A : 是的,但是他们是不一样的。


Q : new OneMoreThan( new OneMoreThan( new OneMoreThan(new Zero())))和哪个数概念相似?

A : 3


Q : Num 比 boolean 多吗?

A : 多很多。


Q : 比 int 多吗?

A : 不。


Q : 说下 new Zero() 和 0 的区别呢?

A : 我们得区别它们。new Zero() 是 Zero 的一个实例,意味着也是 Num 。0 是一个 int。


Q : 正确。不同数据类型的实例就是不同的。

A : 类型是一系列实例的统称。


Q : 基本类型(int 和 boolean)是不同的。

A : 那些不是基本类型呢?


Q : 类定义不引入基本类型,比如上面提到的 new Zero() 不单单是 Zero 的实例,也是 Num。任何继承 Num 的数据类型都是。

A : 然后呢?


Q : 就像每个数据类型继承 Object。

A : 就是说,所有类都是一个对象。


Q : 正确,下面有所体现。

A : 好的。


建议一:
自定义数据类型时,使用抽象类
自定义具体数据类型时,使用 extends 关键词继承抽象类


Q : 看看下面的定义?

abstract class Layer {}
class Base extends Layer {
    Object o;
    Base(Object o) {
        this.o = o;
    }
}
class Slice extends Layer {
    Layer l;
    Slice(Layer l) {
        this.l = l;
    }
}

A : 定义了 Layer 抽象数据类型和其两个具体数据类型 Base 和 Slice。其中 Base 包含一个值对象 Object。


Q : new Base(new Zero()) 是什么?

A : 一个 Base 的实例,即是 Layer 又是 Object 的实例。


Q : new Base(new Salt()) 是什么?

A : 一个 Base 的实例。但 new Base(new Salt())new Base(new Zero()) 是同一个数据类型吗?


Q : 是的。因为对象实例由 new 关键字创建,而它们都是 Base。

A : 因为 Base 包含的值对象是 Object。所以可以是 new Salt()new Zero()


Q : 任何都是个 Object 吗?

A : new 关键字创建的都是对象。自然 String 、Arrays 也是对象,这里我们不展开讲。


Q : 是的。下面的是 Layer 实例吗?

new Base(5)

A : 5 没有通过 new 创建,所以这个错误的语法。


Q : 下面的是 Layer 实例吗?

new Base(false)

A : false 没有通过 new 创建,所以这个错误的语法。


Q : 下面的是 Layer 实例吗?

 new Base(new Integer(5))

A : 是的。 new Integer(5) 创建了一个 int 对象。


Q : 那么怎么创建一个 Layer 实例拥有 false?

A : 简单:

 new Base(new Boolean(false))

Q : int Integer / boolean Boolean 混乱了?

A : 以后会涉及到。


Q : 期待更多吧。

A : 迫不及待。

Posted in 技术, 网络

用 Wireshark 图解:TCP 三次握手

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢!

tcp00

“snow warn throughout the winter”

一、什么是 Wireshark ?
简单地说,Wireshark 是抓包工具。官网说,“Wireshark 是一个网络包分析工具。 网络数据包分析仪将尝试捕获网络数据包并试图尽可能详尽显示该数据包。”

推荐一本书《Wireshark 网络分析就这么简单》,Wireshark 工具下载地址 https://www.wireshark.org/download.html。

Wireshark 不单单能抓包,主要的 Features 是对数据包进行各种的分析。下载打开界面非常简单直观:

tcp01

最上面是 Packet List 窗口,它列出了所有网络包。

在 Packet List 中选定的网络包会详细地显示在中间的 Packet Details 窗口中。

最底下是 Packet Bytes Details 窗口(16 进制数据),我们一般不会用到它。

 

二、我们抓什么包呢?如题 TCP
TCP 一脸懵逼。记得上次在 《图解Http协议》得知,HTTP 是一个客户端和服务器端请求和响应的标准TCP。其实建立在 TCP 之上的。那我们就抓 HTTP,这很简单。

 

三、实操 Wireshark

选择 Capture – Options,选择当前网络,点击 Start 。如图:

tcp02

浏览器打开我的博客 www.bysocket.com ,然后在 Wireshark 中的过滤器输入博客 IP 过滤:ip.addr == 106.14.40.18

选择第一行,如第一张图,简单介绍下 Packet Details 窗口参数详情:

Frame – 物理层
Ethernet – 数据链路层
Internet Protocol Version – 网络层
Transmission Control Protocol – 传输层

大家知道 网络层次划分为 标准的OSI七层模型,还有 TCP/IP四层协议 以及 TCP/IP五层协议。如图:

其中,Transmission Control Protocol – 传输层是我们最为关心的。如图已经展开了:

tcp04

具体我们先学习 TCP 报文段格式:

tcp05

那么第二个红框,由上至下,一一大家可以对应下,重点的是:
Sequence number – 序号
Acknowledgment number – 确认号
Flags – 标志位
— Acknowledgment 确认位
— Push 急迫位
— Reset 重置位
— Syn 同步位
— Fin 终止位

a. 第一次握手标志位
localhost Seq=0 -> 博客地址
从标志位看出,同步位有值,在做请求(SYN):Syn 同步位为1
tcp06

 

b. 第二次握手标志位
博客地址 Seq=0 Ack=1 -> localhost
从标志位看出,确认位、同步位有值,在做应答(SYN+ACK):Syn 同步位为 1 、Acknowledgment 确认位为 1
tcp07

c. 第三次握手标志位
localhost Seq=1 Ack=1 -> 博客地址 (注: Seq=Seq+1)
从标志位看出,只有确认位有值,在做再次确认(SYN):Acknowledgment 确认位为 1
tcp08
综上所述,一个完整的三次握手就是:请求(SYN) — 应答(SYN+ACK) — 再次确认(ACK)

tcp09

如以上文章或链接对你有帮助的话,别忘了在文章结尾处评论哈~ 你也可以点击页面右边“分享”悬浮按钮哦,让更多的人阅读这篇文章。

Posted in 清文

、北京北京

北京北京

单曲循环汪峰的歌

写下对北京的回忆

几词文,几处景,两友人,一米厂

糖葫芦

大包子

油条

还有第一晚可怕的雾霾

凌晨落地的景色,候机前写了

《试错》

是不是你和我一样

每当夜深安静迷茫

总是想的太多

却每次都被时间浇熄

30岁的眼泪

还是那么不切实际

盼望地

以为爱情能解脱生活的狼狈

所以别要求太多

不错过那些努力可以解决的东西

无法长大

也就不要学着别人挣扎

往想去的地方飞

走过看过听过去试错

然后去了第一处景

北京 798 艺术区

知道了

曹勇(画家)

一位由画而生的旅者

说过

“人的生命很短暂,一定要到绘画的最高舞台去。”

停下买了个糖葫芦,写了

《穿越文艺区》

摄影展

先穿越到照片当时当地

手机没电了

停下步来

随处而安喝一小杯

充会电

再前行

切景至天安门

不想多说 人多

晚上寄宿友人

聊拉家常

约早另一友人

逛米厂中

和现在工作一样呼吸节奏

听说老雷

在对面那个高楼中

眺望

昨夜的大风

刮走了雾霾

漫步人少的颐和园里

止步写了两句

秋离冬至踏园中

高柳随风舞骚影

然后

北京北京

再会