Blacktea's Life

A programmer who love music and football


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

  • 公益404

Mac上使用intelliJ开发WEbServer(Servlet)、mysql的新手教程

发表于 2017-04-09 | 分类于 server | 阅读次数

基础概念

什么是Servlet

1
Servlet是Java提供的用于开发Web服务器应用程序的一个组件,运行在服务器端,由Servlet容器所管理,用于生成动态的内容。Servlet是平台独立的Java类,编写一个Servlet,实际上就是按照Servlet规范编写一个Java类。

什么是JSP

1
JSP是Servlet的一种特殊形式,每个JSP页面就是一个Servlet实例——JSP页面由系统编译成Servlet,Servlet再负责响应用户请求。JSP其实也是Servlet的一种简化,使用JSP时,其实还是使用Servlet,因为Web应用中的每个JSP页面都会由Servlet容器生成对应的Servlet。对于Tomcat而言,JSP页面生成的Servlet放在work路径对应的Web应用下。

IntelliJ开发WebServer

Demo源码github地址

https://github.com/blackteachinese/servletDemo

搭建Webserver工程环境

  • 创建一个Maven Demo工程

  • 项目名称右键,选择”Add Framework Support”

  • 添加Web Application

  • 添加完后可以看到WebServer的目录

  • 配置Artifact打包部署设置

  • 配置Tomcat服务器

  • Maven依赖配置

开发一个Get请求接口

  • 创建一个formGetApi.html,做为表单承载页
  • 在Index.jsp配置跳转到formGetApi.html页面
  • 创建一个继承于HttpServlet的Java类GetApiTest
    • 你会发现HttpServlet找不到。不用急,选中“HttpServlet”按“option”+”enter”,点击添加Maven依赖,导入HttpServlet的依赖即可。

  • 重载HttpServlet的“service”方法。通过“getParameter”和“getParameterValues”获取表单的字段,并将获取到的结果输出回浏览器。
  • web.xml里配置api的映射

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    <servlet>
    <servlet-name>GetApiServlet</servlet-name>
    <servlet-class>GetApiTest</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>GetApiServlet</servlet-name>
    <url-pattern>/getApi</url-pattern>
    </servlet-mapping>
    </web-app>
  • 启动Tomcat

    开发一个Post请求接口

  • 创建一个formPostApi.html。唯一的不同是对”method”的设置。
  • 创建一个继承于HttpServlet的Java类PostApiTest。
    • post请求需要先对request、response对象设置CharacterEncoding
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
      // right to read chinese
      req.setCharacterEncoding("utf-8");
      // right to output chinese
      resp.setContentType("text/html;charset=utf-8");
      PrintWriter out = resp.getWriter();
      // get name value
      String name = req.getParameter("name");
      out.println("<h1>Hello,"+name+"</h1>");
      // get info value
      String[] infos = req.getParameterValues("info");
      if (infos != null) {
      out.print("<h1>info :</h1>");
      for (String contact :infos) {
      out.print("<h1>"+contact+"</h1>");
      }
      }
      }

使用mysql储存提交的表单数据

  • 创建一个formMysqlApi.html页面
  • web.xml映射配置
  • 创建一个继承于HttpServlet的Java类MysqlApiTest。

    mql操作

IntelliJ添加一个Datasource


mysql命令行创建一个DataBase

IntelliJ创建一个createDB.sql文件,创建userInfo表

mysql命令行设置userInfo表character为UTF8

IntelliJ创建一个insertDB.sql文件,插入一条数据

动态加载mysql驱动

1
Class.forName("com.mysql.jdbc.Driver");

JDBC连接MySQL

1
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/webserverDemo?user=root&password=19880622");

环境介绍

IntelliJ环境搭建

mysql环境搭建

常用mysql命令

  • 连接mysql:
    • 格式: mysql -h主机地址 -u用户名 -p用户密码
    • example:mysql -uroot -p
  • 退出MYSQL命令
    • 格式:exit (回车)
  • 创建数据库
    • 命令:create databas <数据库名>;
  • 显示数据库
    • 命令:show databases;
  • 连接数据库
    • 命令: use <数据库名>
  • 创建数据库表
    • 命令:create table <表名> ( <字段名1> <类型1> [,..<字段名n> <类型n>]);
  • 删除表
    • 命令:drop table <表名>
  • 插入表数据
    • 命令:insert into <表名> [( <字段名1>[,..<字段名n > ])] values ( 值1 )[, ( 值n )]
  • 查看表中所有数据
    • 命令: select <字段1,字段2,…> from < 表名 > where < 表达式 >
    • example:select * from MyClass;

MySQL的JDBC URL格式

1
jdbc:mysql//[hostname][:port]/[dbname][?param1=value1][&param2=value2]….

Example:

1
jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password

巴菲特的投资思维如何用于日常生活

发表于 2017-04-04 | 分类于 思维 | 阅读次数

学会权衡风险与收益

首先,我们做事情要有明确的目的,不同的目的要采用不同的方法。
大部分人在生活中很容易受别人影响。
看到朋友给他的孩子报了钢琴、英语、绘画等兴趣班,就想象自己的孩子会落后于别人,赶紧自己也给孩子报了相应的培训班。

危机意识敏锐是人类进化的优良习惯。在原始森林里,当你看到身边的人突然加速逃跑的时候,如果你非常理智思考一下,观察一下身边的情况,你很可能就野兽吃了。于是活下来的都拥有容易受他人影响的基因。但现代生活比原始森林复杂多了,光依靠过去的本能的反应已经远远不够了。我们应该明确好自己的目标,而不是别人给孩子报英语,我们就不加思索的也报英语。

那我们应该怎么做?每个孩子有着不一样的基因,各方面的能力不一样,兴趣爱好也不一样。譬如,你发现自己孩子对音乐特别敏感,听到音乐会跟着哼、身体跟着节奏舞动。那说明你的孩子对音乐、舞蹈比较敏锐,可以尝试往这个方向引导。于是这就成为你权衡给孩子哪些教育其中一个目标。即便是要给孩子报兴趣班,也要依据你积累下来的这些目标和方向。不盲目跟风。

切莫好高骛远。

我们在制定目标时不能好高骛远。如果你好高骛远,那么你定的目标通常会没有可执行性。

比如你定下这样的目标,“我今年的理财投资回报率要达到30%”。有些人可能会觉得也并不是很难,牛市的时候几个涨停就够了。天了噜,巴菲特每年的投资回报率就12%左右。他养着一个全球最贵的投资团队,每天分析各行业趋势、各国政策的影响、企业的动态,最后收益也就平均12%。

我并非说没有任何人的投资的回报能高于巴菲特,只是非常少,可能低于5%。而且即便你某一年投资回报高于巴菲特并不代表你平均每年投资回报率能高于巴菲特,也就是说你的投资策略、投资能力并不优于巴菲特,只是刚好今年的投资运气特别好。这其实又说到另外一个主题,是关于自我认知能力,大部分人的自我认知能力都很差,这个且不说。

在生活中好高骛远会带来什么实际性的错误呢?就像上面的例子,如果你定的理财回报率是30%,那你就会关注到很多风险极高的投资产品。比如一些区块链的垃圾币包装的理财产品、期货产品。你也更容易被别人忽悠去买这些风险极高、甚至完全是骗局的传销型理财产品。如果你定的目标是30岁前实现财富自由,你可能就会忽视基础的积累,只去做那些看起来有可能的事情。比如买彩票、盲目创业、高风险投资。你买股票时可能会加5倍杠杆,不翻倍的投资你不会考虑。

权衡回报和风险

我们需要考虑的是回报和风险的比例,而不仅仅是回报本身。
是的,我们常常听别人说这个回报率是10%非常高,这个回报率是12%相当赞。但却很少有人说,这个理财产品往年的实际投资回报是多少。多大的百分比是亏损、多大的百分百是0%~5%之间。大家都对风险的分析做得不够,能大概知道A产品风险较低、B产品风险高一点就已经很不错了。更别提最后通过概率权的思想计算出实际的投资回报率(而不是发行方包装的回报率)。

在生活中我们同样要学会权衡回报和收益。比如:周六有个李开复的讲座要不要去听。

  • 先算一下要花的时间。
    • 路上时间+讲座时间,共6个小时
  • 初步预计一下收益。
    • 认识几个行业朋友?听到李开复对人工智能的干货?感受一下气氛,激发一下自己的热情?
  • 替代方案/机会成本
    • 陪老婆孩子
    • 看半本书
    • 打场球锻炼一下
    • 花两个小时看视频直播,省下4个小时干别的。

切换有成本

最后,任何事情都有一个准入的成本,或者说切换的成本。大到换工作,小到换手机,换电脑,都是如此。到新单位前三个月乃至半年,要重新学习和适应,其实做不了太重要的事情,这就是准入成本。换一台电脑,很多旧的文件要导出来,要装新软件,这都是准入成本。考虑到准入成本,你就不应该切换工作太频繁,在一个公司待不到2年通常都是一件成本较高的事情。

PS:这些思想听起来是很简单道理,大家或多或少都听过这样的说法,但平时却很难做不到。这是由于我们长久以来形成的错误的思维习惯,你不下意识去纠正,即便听过N遍也很难真正吸收。

比天赋更重要是什么?

发表于 2017-03-29 | 分类于 思维 | 阅读次数

一 .优势积累比天赋更重要

机遇比天赋更重要

加拿大著名球队老虎队的队员里25个球员,有17个球员的出生日期在1~3月。为什么有么明显的倾向性?加拿大冰球选拔机制是按年龄分组,5岁一组、6岁一组。同样是1990年出生,1月份出生的小孩和12月份出生的小孩分在一组。对于小孩来说差了10几个月,身体发育就差很多,年初出生的球员就占据很大的优势。所以年初出生的小孩一开始表现就会更好,表现更好就会被筛选到特训组,得到更好的训练。得到更好的训练,表现就更好,如此不断积累优势,最后年初出生的小孩称为顶级球员的机率就大大提升。

知道一万小时理论也没用

不是每个人都有机会在合适的时机进行一万小时的训练。比如加拿大的冰球运动员,如果你小的时候进不了第一梯队,就没能进行优质的训练,很难达到一万小时。而且年龄大了再完成一万小时的训练也没有用了,因为运动员的身体条件高峰期是受年龄限制的。

社会环境变革比努力重要得多

70后毕业参加工作买一套房子,相当于80后工作10年。最近毕业的清华大学学生,买不起北京房子不要太多。

二.文化背景对成功影响很大

20世纪90年代韩国大航航空公司飞机失事率是同期美国联合航空的17倍,但究其原因竟然不是飞机设备、也不是管理问题。他们做了大量调研,听取飞机黑匣子录音,最终发现韩国文化是最根本的原因。因为韩国是一个等级分明的国家。在飞行过程中,机长做了一些错误的决策,副机长以及其他成员不敢说,没有了其他成员的有力监督,飞机失事率就变高了很多。

我们该怎么做

挤入第一梯队

学习和工作时要想办法进入“第一梯队”,这样才能获得高质量的训练,加速积累达到一万小时的训练,从了增加优势积累的机会。

如何获得社会变革红利

花时间研究未来趋势,训练自己的预见能力,并且在未来趋势到来之前,开始一万小时的积累。比尔盖茨在大家还没用电脑前,就有了计算机编程的10万小时积累。
我们需要一点运气,找到风口并且在风口前已经做好了准备。

内存泄漏监控

发表于 2017-03-14 | 分类于 iOS | 阅读次数

为什么要做app内存泄漏监控?

内存泄漏将导致app内存占用变大,成为iphone要kill App的时候优先考虑的对象.

监控内存泄漏的时机

  1. UIViewController调用”dismissViewControllerAnimated:”的时候
  2. UInavigationController调用”popToRootViewControllerAnimated:”等pop方法
  3. UITabbbarViewController、UIPageViewController、UISplitViewController+MemoryLeak需要释放时,对应的内嵌视图控制器也需要释放。

监控小技巧

创建一个block,block持有需要释放的视图的weak指针,当监测时机到时,执行这个block,如果weak指针不为nil,则该试图已经内存泄漏了。

监控对象

  1. 所有需要释放的视图控制器
  2. 视图控制器的View,及其每一层嵌套的Subview

视图树的记录

监测到内存泄漏后,为了方便开发定位到具体泄漏的视图,我们可以泄漏的视图树记录下来。

泄漏后如何及时提醒

泄漏后怎么提醒开发者比较合适呢。

  1. 发现泄漏马上把泄漏的视图树log打印出来
  2. 悬浮一个提醒款,显示当前泄漏的数量
  3. 命中断言(会阻断开发,容易被喷)

匠人精神的重要性

发表于 2017-01-15 | 分类于 default | 阅读次数

最近常听到“匠人精神”这个词。难道资本寒冬的来临,让大家突然醒悟,光靠包装、概念就轻松能拿到融资创业的时机已经过去了?

什么是匠人精神?

第一次听说这个词汇,我脑海里浮现的是一个打铁匠的老师傅。一个勤勤恳恳、认真、古板的手艺人。这应该是很少的一部分人吧。直到最近看了晓松奇谈关于“探寻匠人精神”的节目,才对匠人精神有了新的体会。
一位炸了50多年天妇罗的“早乙女哲哉”说了一句话:”我觉得日本这几十年好像没有什么变化“。要知道这几十年日本可是经历过七八十年代经济腾飞、到1990经济泡沫后的一蹶不振。难道他对外界的感知能力这么弱吗?这有一定关系,但除此之外还和早乙女哲哉对生活和工作的专注有关系。他是一个专注于做好一件事的人,这几十年一直致力于炸天妇罗,不受经济环境的变动,不受身旁人们的价值观的影响,不去关心最近股票的走势,房价是不是又涨了、谁家做了什么生意又发财了、什么行业现在在风口。这放在当今的中国,就是一个稳重、古板的手艺人,不懂得变通,不懂人情世故、不懂理财的人。这绝不是国内老百姓们希望成为的人。
这是一种专注的精神,专注得来还很有安全感,让你安心去专注,不受外界影响。这确实很不容易,这是我一直比较缺乏的精神,也是我们缺乏的精神。我从小到大是一个懒散、随便的人。做很多事情都不追求细致、完美,一直不知道自己喜欢什么,很难专注认定一件事去做坚持一直做。
除了专注精神,我还能体会到一种叫“精进”的精神。“幸村”开了一家小的料理店,从默默无名到米其林1星,再到米其林3星,竟然菜单一直没有换过。那这么多年,这家店难道一直不思进取、没有进步吗?在我北京各种有名的餐厅,几个月就得换菜单,而客户也很乐于去品尝新菜。而幸村说到:“多年来我们没有改变菜单,不是说我们就没有去创新、没有去思考和尝试如何变得更好,而是我们一直在研究我们原有的料理如何做得更好,我们一直在改进我们的菜品”。我认为这就是一种“精进”的精神,我们不满足于好,还可以不断继续做得更好,而不一定非得做各种新的事情,去证明自己什么都好。
专注、精进的精神看似和创新精神有矛盾,其实不然。最近一直很流行的”1万小时“理论告诉我们,专注在一个领域里足够长的时机,人人都能成为专家。如果我们能在同一个领域里,积极去思考也能相处很多有创意的想法,当然我们不能所有新想法都去尝试。我们可以在这些新想法里,选择自己最认可的一个想法,坚持一段时间(比如1个月)去做,如果达到预期,我们再坚持更长的时间”精进“地去做。切忌同时多点开发,一件事情没做到阶段性的时间,看到别的事情有机会就换了。
是的,创新对于世界的发展异常重要,但对于我们个人而言,在自己有限的时间里,做好选择并专注地去做,不断得精进自己的专项技能更重要。想一想,人人都有自己所专注和精进的领域做深、做细,这个社会便有很多不同领域的事业在专注、精进地发展。也许很多人会说,不可能,你必须什么技能都懂,你才能把事业做大。这有一定的道理,补助性的技能我们也需要投入一定时间去学习,比如制作PPT能力、外语能力、基本的社交能力、协作能力等等。但得主次分明,不能搞不清楚自己的专项领域。要相信现在的分工越来越细、只要各种专项的技能能够合理协作,都能干成足够大的事业。

iOS侧滑出现的卡死Bug

发表于 2016-12-30 | 分类于 iOS | 阅读次数

我们都知道iOS7以后,系统UINavigationController自带侧滑返回上一级。它是通过navigationController中的interactivePopGestureRecognizer属性来控制。

某一天测试妹妹跑过来跟我说,我测出一个bug,进去某一个页面后回到RootViewController,左滑会导致视图堆栈变乱。我试了一下,果真如此。我想起以前曾经遇到一个bug,如果是自定义UINavigationController并且设置了自定义的leftBarButtonItem,那在UINavigationController的rootViewController上滑动返回时,会出现界面卡死的情况。

赶紧查了一下我们的自定义XXNavigationController,缺失设置了leftBarButtonItem。但是仔细查看了代码,我们其实是禁止了rootViewController左滑返回的事件。

1
2
3
4
5
6
7
8
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer == self.interactivePopGestureRecognizer) {
if (self.viewControllers.count <= 1 ||
self.visibleViewController == [self.viewControllers firstObject]) {
return NO;
}
return YES;
}

天了噜!这应该没有问题的,什么情况。经过一番仔细查看,发现只有进入某个页面,左滑才会出这个问题。到底这个做了什么?终于被我发现一行要命的代码。

1
self.navigationController.interactivePopGestureRecognizer.delegate = nil;

interactivePopGestureRecognizer的代理被设置成nil了。。。。
怎么处理好呢?

首先,创建一个类XXXDelegate专门处理侧滑手势的delegate事件。并实现上面“gestureRecognizerShouldBegin:gestureRecognizer”方法的处理。

接着,在XXTabbarController把每个NavgationController对应创建一个XXXDelegate。每次回到TabbarController任意一个子页面“viewDidAppear”的时候,把对应ChildViewController的NavgationController的interactivePopGestureRecognizer.delegate设置成对应的XXXDelegate;

结论,这样不论哪个页面把interactivePopGestureRecognizer的代理设置成nil,都能保证回到rootViewController,interactivePopGestureRecognizer.delegate都能设置成功。

iPhone的屏幕像素

发表于 2016-10-24 | 分类于 iOS | 阅读次数

iPhone设备的尺寸分辨率表

分辨率

分辨率就是屏幕上横、纵的总象素点数

物理分辨率

  • 单位px
  • 上图physic pixel都是物理分辨率

逻辑分辨率

  • 单位pt

iPhone 6+

除了iPhone 6+,其他所有iPhone的PPI都是326,用@2x的素材。而6+的PPI是401,理论上应该用401/326*@2=@2.46的素材。但是这个比例很难切图,所以苹果让6+用@3x的素材,然后再将@3x缩放87%到@2.46。
按照这个逻辑,物理分辨率/虚拟分辨率=87%。

虚拟分辨率高度= 1920/0.87 = 2208
虚拟分辨率宽度= 1080/0.87 = 1242

这样开发的时候针对6+就准备@3x的素材就好了

基本单位

英寸
1 inch = 2.54cm = 25.4mm
屏幕尺寸
我们通常所说的iPhone5屏幕尺寸为4英寸、iPhone6屏幕尺寸为4.7英寸,指的是显示屏对角线的长度(diagonal)。
像素密度PPI
PPI(Pixel Per Inch by diagonal):表示沿着对角线,每英寸所拥有的像素(Pixel)数目。
PPI数值越高,代表显示屏能够以越高的密度显示图像,即通常所说的分辨率越高、颗粒感越弱。
缩放因子Scale

Scale的起源

  • 早期的iPhone3GS的屏幕分辨率是320*480(PPI=163),iOS绘制图形(CGPoint/CGSize/CGRect)均以point为单位(measured in points):
1
1 point = 1 pixel(Point Per Inch=Pixel Per Inch=PPI)
  • 后来在iPhone4中,同样大小(3.5 inch)的屏幕采用了Retina显示技术,横、纵向方向像素密度都被放大到2倍,像素分辨率提高到(320x2)x(480x2) = 960x640,PPI从163提升2倍到326(PPI=326),显像分辨率提升至iPhone3GS的4倍(1个Point被渲染成1个2x2的像素矩阵)。
    但是对于开发者来说,iOS绘制图形的API依然沿袭point(pt,注意区分印刷行业的“磅”)为单位。在同样的逻辑坐标系下(320x480):
1
2
1 point = scale*pixel
(在iPhone4~6中,缩放因子scale=2;在iPhone6+中,缩放因子scale=3)。
  • scale计算公式:
1
scale=绝对长度比(point/pixel)=单位长度内的数量比(pixel/point)

参考

dp、sp、px傻傻分不清楚

TodayExtension入坑指南

发表于 2016-04-14 | 分类于 default | 阅读次数

添加Today Extension

File > New > Target > Application Extension > Today Extension

_2016_08_18_12_01_36

Widget和主程序共享数据

App Groups
iOS8以后,同一个开发者账号可以通过group共享资源,我们可以通过App Groups,共享Widget和程序的NSUserDefaults的数据

  • 注意:suiteName必须和dev center中定义的app group的identifier ID一致
  • App的Target和Widget的Target都要设置为同一个group
    1
    NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:@"group.blacktea"];

_2016_08_17_7_48_46

同过Widget插件启动App

NSExtensionContext

  • 主程序设置URL Schemes

    _2016_08_17_11_42_19

  • 通过UIViewController的extensionContext属性,可以通过Scheme启动App主程序

1
[self.extensionContext openURL:[NSURL URLWithString:@"blacktea://finished"] completionHandler:nil];

调整Widget尺寸

设置preferredContentSize

  • 设置宽度是不生效的,默认是整屏的宽度,直接设置高度即可
1
self.preferredContentSize = CGSizeMake(0, 80 * 3);

调整Widget的Edge

1
2
3
4
5
6
7
8
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)margins
{
margins.bottom = 10.0;
margins.left = 0;
margins.right = 0;
margins.top = 10.0;
return margins;
}

系统通知用户刷新界面

系统会在适当的时候让Widget刷新数据。可以做一些网络数据请求,并更新Widget视图的数据。

  • 需要实现NCWidgetProviding协议和widgetPerformUpdateWithCompletionHandler方法
1
2
3
4
5
6
7
8
9
10
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResultFailed
// If there's no update required, use NCUpdateResultNoData
// If there's an update, use NCUpdateResultNewData
// 网络请求,成功或失败通过completionHandler告知系统
completionHandler(NCUpdateResultNewData);
}

Widget 调试

  • 调试

需要通过Debug设置才能对Wigget代码进行调试
Debug > Attach to Process by PID or Name

_2016_08_18_11_17_49

  • Log

Widget的Log需要通过Devices的console查看
Windows > Devices > 对应的设备

_2016_08_18_11_29_49

1…34
Blacktea

Blacktea

iOS music footbood barcelona 歌手、程序员、爵士乐、巴萨罗那、自由主义者、学生

38 日志
14 分类
35 标签
RSS
GitHub 微博 豆瓣 知乎
© 2017 - 2019 Blacktea
由 Hexo 强力驱动
主题 - NexT.Pisces