分类 Java 下的文章

Linux下JDK到底应该安装在哪儿?

最标准的jdk安装路径是:
/usr/local/java/jdk1.6.0_38
/usr/local/java/jdk1.8.xxx
注意:几个不同的jdk可以共存,都放在/usr/local/java/下
然后在/etc/profile里面export JAVA_HOME指定默认的jdk
Linux 目录结构:

/bin 用来贮存用户命令。/usr/bin 也被用来贮存用户命令。
/sbin 许多系统命令(例如 shutdown)的贮存位置。/usr/sbin 中也包括了许多系统命令。
/root 根用户(超级用户)的主目录。
/mnt 该目录中通常包括系统引导后被挂载的文件系统的挂载点。比如,默认的光盘挂载点是 /mnt/cdrom/。可以为U盘建一个挂载点:mkdir /mnt/usb。
/boot 包括内核和其它系统启动期间使用的文件,最大不超过200M。通常我为 /boot 建一个primary分区是1G。
/lost+found 被 fsck 用来放置零散文件(没有名称的文件)。
/lib 包含许多被 /bin 和 /sbin 中的程序使用的库文件。目录 /usr/lib 中含有更多用于用户程序的库文件。/lib 目录下放置的是 /bin 和 /sbin 目录下程序所需的库文件。简单说,/lib 是内核级的;/usr/lib 是系统级的;/usr/local/lib 是用户级的。仅仅被 /usr 目录下的程序所使用的共享库不必放到 /lib 目录下。只有 /bin 和 /sbin 下的程序所需要的库有必要放到 /lib 目录下。
/dev 贮存设备文件。
/etc 包含许多配置文件和目录。
/var 用于贮存variable(或不断改变的)文件,例如日志文件和打印机假脱机文件,虚拟机镜像文件等。
/usr 包括与系统用户直接有关的文件和目录,例如应用程序及支持它们的库文件。
/proc 一个虚拟的文件系统(不是实际贮存在磁盘上的),它包括被某些程序使用的系统信息。
/initrd 用来在计算机启动时挂载 initrd.img 映像文件的目录以及载入所需设备模块的目录。不要删除 /initrd 目录。如果你删除了该目录后再重新引导 Red Hat Linux 时,你将无法引导你的计算机。
/tmp 用户和程序的临时目录。 /tmp 给予所有系统用户读写权。
/home 用户主目录的默认位置。
/opt 可选文件和程序的贮存目录。该目录主要被第三方开发者用来简易地安装和卸装他们的软件包。

在传统的unix系统中,/usr 通常只包含系统发行时自带的程序,而/usr/local 则是本地系统管理员用来自由添加程序的目录。这里有一条严厉而牢固的规则:除非在里面创建目录,unix发行版不得使用 /usr/local 。
对于Linux发行版,如 RedHat, Debian 等等,一个可能的规定是:/usr 目录只能由发行版的软件包管理工具负责管理,而对 /usr/local 却没有这样做。正是因为采用这种方式,软件包管理工具的数据库才能知道在 /usr 目录内的每一个文件。下面演示 Ubuntu 系统下如何安装JDK和配置环境变量。
如果你的计算机仅仅作为开发使用时推荐使用这种方法. 所有用户的shell都有权使用这些环境变量。修改 /etc/profile 文件,执行下面的语句:

$ sudo -s
# echo 'export JAVA_HOME=/usr/local/java/jdk1.6.0_38' >> /etc/profile
# echo 'export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH' >> /etc/profile
# echo 'export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar' >> /etc/profile

切换到任何一个用户,执行下面这个命令,环境变量的更改立即生效:
# source /etc/profile
检查JAVA环境变量更改是否生效:
$ java -version

SSH 免密登录

若A想免密登录到B,将A生成的公钥追加到B的/home/.ssh/authorized_keys文件中即可

//在A(192.168.X.2)服务器下执行:
//生成公钥
Portal@ubuntu:~$ ssh-keygen -t rsa -P ''
//将公钥拷贝到目标服务器的临时文件夹下
Portal@ubuntu:~$ scp .ssh/id_rsa.pub Portal@192.168.X.84:/home/Portal/id_rsa.pub
//在B(192.168.X.84)服务器下执行:
//将公钥追加到该文件中
Portal@ubuntu: ~$ cat id_rsa.pub >> .ssh/authorized_keys

在机器上自己做SSH免密登录:

cd ~/.ssh/                     # 若没有该目录,请先执行一次ssh localhost
ssh-keygen -t rsa              # 会有提示,都按回车就可以
cat id_rsa.pub >> authorized_keys  # 加入授权
chmod 700 ./authorized_keys    # 修改文件权限

list删除指定元素

/*
* 错误
*/
public static void remove31(List list, String target){
Iterator iter = list.iterator();
while (iter.hasNext()) {
String item = iter.next();
if (item.equals(target)) {
list.remove(item);
}
}
print(list);
}
/*
* 正确
*/
public static void remove32(List list, String target){
Iterator iter = list.iterator();
while (iter.hasNext()) {
String item = iter.next();
if (item.equals(target)) {
iter.remove();
}
}
print(list);
}

接口幂等性

接口的幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终得到的结果是一致的。有些接口可以天然的实现幂等性,比如查询接口,对于查询来说,你查询一次和两次,对于系统来说,没有任何影响,查出的结果也是一样。
除了查询功能具有天然的幂等性之外,增加、更新、删除都要保证幂等性。
在分布式环境中,操作互斥性问题和幂等性问题非常普遍。经过分析,我们找出了解决这两个问题的基本思路和实现原理,给出了具体的解决方案。
针对操作互斥性问题,常见的做法便是通过分布式锁来处理对共享资源的抢占。分布式锁的实现,很大程度借鉴了多线程和多进程环境中的互斥锁的实现原理。只要满足一些存储方面的基本条件,并且能够解决如网络断开等异常情况,那么就可以实现一个分布式锁。目前已经有基于Zookeeper和Redis等存储引擎的比较典型的分布式锁实现。但是由于单存储引擎的局限,我们开发了基于ZooKeeper和Tair的多引擎分布式锁Cerberus,它具有使用灵活方便等诸多优点,还提供了完善的一键降级方案。
针对操作幂等性问题,我们可以通过防止重复操作来间接的实现接口的幂等性。GTIS提供了一套可靠的解决方法:依赖于存储引擎,通过对不同操作所对应的唯一的内容特性生成一个唯一的全局ID来防止操作重复。
目前Cerberus分布式锁、GTIS都已应用在生产环境并平稳运行。两者提供的解决方案已经能够解决大多数分布式环境中的操作互斥性和幂等性的问题。值得一提的是,分布式锁和GTIS都不是万能的,它们对外部存储系统的强依赖使得在环境不那么稳定的情况下,对可靠性会造成一定的影响。在并发量过高的情况下,如果不能很好的控制锁的粒度,那么使用分布式锁也是不太合适的。总的来说,分布式环境下的业务场景纷繁复杂,要解决互斥性和幂等性问题还需要结合当前系统架构、业务需求和未来演进综合考虑。Cerberus分布式锁和GTIS也会持续不断地迭代更新,提供更多的引擎选择、更高效可靠的实现方式、更简捷的接入流程,以期满足更复杂的使用场景和业务需求。

Servlet、Spring MVC和 Struts2线程安全

Struts 2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。
Spring的Ioc容器管理的bean默认是单实例的,上一次请求处理的状态信息被保持下来,并影响了下一次的请求,实际上就是Action中的类变量被不同的请求读取,出现错误结果
解决:就是不用单例, spring中bean的作用域设为prototype,每个请求对应一个实例.

js中return null和return false的区别

1. return返回null,起到中断方法执行的效果,只要不return false事件处理函数将会继续执行,表单将提交
2. return false,事件处理函数会取消事件,不再继续向下执行。比如表单将终止提交
这里面的return含有一些细节知识:
例如:onClick=’return add_onclick()’与 onClick=’add_onclick()’的区别
JAVASCRIPT在事件中调用函数时用return返回值实际上是对window.event.returnvalue进行设置。
而该值决定了当前操作是否继续。
当返回的是true时,将继续操作。
当返回是false时,将中断操作。
而直接执行时(不用return)。将不会对window.event.returnvalue进行设置
所以会默认地继续执行操作
在onclick事件上这样处理的

<input type="submit"  onclick="fun1();return false;" />

这样fun1既可以写自己想要的效果,return false 也可以取消默认的刷新行为

MyBatis获取刚刚插入对象的id

适用于对于支持自动生成主键的数据库
一、数据库表中ID的设计
id int型 自动递增
二、MyBatis的Mapper
useGeneratedKeys=”true” keyProperty=”id” 是重点

	<insert id="insert" useGeneratedKeys="true" keyProperty="id">
		INSERT INTO rdss2_report(
			report_name,
			componets,
			update_date,
			create_date,
			update_by,
			create_by
		) VALUES (
			#{reportName},
			#{componets},
			#{updateDate},
			#{createDate},
			#{updateBy.id},
			#{createBy.id}
		)
	</insert>

三、Java代码
重要代码如下,在保存完对象后,mybatis会自动把ID反填入对象中,直接获取即可

			rdss2ReportService.save(rdss2Report);
			System.out.println("test:"+rdss2Report.getId()+"-"+rdss2Report.getComponets());
	@RequestMapping(value="/saveReport", method=RequestMethod.POST)
	@ResponseBody
	public void saveReport(HttpServletRequest request, HttpServletResponse response,
			@RequestParam Map<String, Object> param) {
		JSONObject jo = new JSONObject();
		try {
			Rdss2Report rdss2Report = new Rdss2Report();
			rdss2Report.setReportName(param.get("title").toString());
			rdss2Report.setComponets(param.get("par").toString());
			rdss2ReportService.save(rdss2Report);
			System.out.println("test:"+rdss2Report.getId()+"-"+rdss2Report.getComponets());
			jo.put("result", "success");
			PrintWriter out = null;
			response.setContentType("application/json");
			out = response.getWriter();
			out.write(jo.toString());
		} catch (Exception e) {
			jo.put("result", "fail");
			PrintWriter out = null;
			response.setContentType("application/json");
			try {
				out = response.getWriter();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			out.write(jo.toString());
			e.printStackTrace();
		}
	}

Spring MVC前端JSON数据传到后端

传送List json
前端发送数据代码:

//准备数据
var componetsArray = new Array();
var dataTmp = {};
dataTmp["component_id"] = panel_biee_components.attr("id");
dataTmp["component_width"] = orgNumIndex;
componetsArray.push(JSON.stringify(dataTmp));
//发送请求
    $.ajax({
        type: "POST",
        url: $("#porjectPath").val()+"/f/report/rdss2Report/saveReport",
        datatype: "json",
        data:{"listParam" : componetsArray},
        success: function(data) {
            alert(data.result);
        }
    });

后端接收参数代码

	@RequestMapping(value="/saveReport", method=RequestMethod.POST)
	@ResponseBody
	public void saveReport(HttpServletRequest request, HttpServletResponse response,
			@RequestParam("listParam[]") List<String> param) {
		JSONObject jo = new JSONObject();
		try {
			System.out.println(param);
			jo.put("result", "success");
			PrintWriter out = null;
			response.setContentType("application/json");
			out = response.getWriter();
			out.write(jo.toString());
		} catch (Exception e) {
			jo.put("result", "fail");
			PrintWriter out = null;
			response.setContentType("application/json");
			try {
				out = response.getWriter();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			out.write(jo.toString());
			e.printStackTrace();
		}
	}

传送Map json复杂数据:
前端发送数据代码:

var componetsArray = new Array();
var dataTmp = {};
dataTmp["component_id"] = panel_biee_components.attr("id");
dataTmp["component_width"] = orgNumIndex;
componetsArray.push(JSON.stringify(dataTmp));
var jsonStr = JSON.stringify(componetsArray);
var jsonObject = {};
jsonObject['title']="标题";
jsonObject['par']=jsonStr;
    $.ajax({
        type: "POST",
        url: $("#porjectPath").val()+"/f/report/rdss2Report/saveReport",
        datatype: "json",
        data:jsonObject,
        success: function(data) {
            alert(data.result);
        }
    });

后端接收参数代码

	@RequestMapping(value="/saveReport", method=RequestMethod.POST)
	@ResponseBody
	public void saveReport(HttpServletRequest request, HttpServletResponse response,
			@RequestParam Map<String, Object> param) {
		JSONObject jo = new JSONObject();
		try {
			System.out.println(param);
			JSONArray ja = JSONArray.fromObject(param.get("par").toString());
			System.out.println(ja.toString());
			jo.put("result", "success");
			PrintWriter out = null;
			response.setContentType("application/json");
			out = response.getWriter();
			out.write(jo.toString());
		} catch (Exception e) {
			jo.put("result", "fail");
			PrintWriter out = null;
			response.setContentType("application/json");
			try {
				out = response.getWriter();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			out.write(jo.toString());
			e.printStackTrace();
		}
	}

superset SQL生成的研究

superset类似系统,一期实现不要实现这么复杂的SQL拼接:

SELECT state AS state,
       job_date AS __timestamp,
       sum(job_num) AS sum_job_num
FROM
  (select count(1) as job_num,
          state,
          job_date
   from job_info
   group by state,
            job_date) AS expr_qry
INNER JOIN
  (SELECT state AS state__,
          sum(job_num) AS mme_inner__
   FROM
     (select count(1) as job_num,
             state,
             job_date
      from job_info
      group by state,
               job_date) AS expr_qry
   WHERE job_date >= STR_TO_DATE('2017-12-05 00:00:00', '%%Y-%%m-%%d %%H:%%i:%%s')
     AND job_date <= STR_TO_DATE('2018-03-15 16:26:53', '%%Y-%%m-%%d %%H:%%i:%%s')
   GROUP BY state
   ORDER BY mme_inner__ DESC
   LIMIT 50) AS anon_1 ON state = state__
WHERE job_date >= STR_TO_DATE('2017-12-05 00:00:00', '%%Y-%%m-%%d %%H:%%i:%%s')
  AND job_date <= STR_TO_DATE('2018-03-15 16:26:53', '%%Y-%%m-%%d %%H:%%i:%%s')
GROUP BY state,
         job_date
ORDER BY sum_job_num DESC
LIMIT 50000

上边是superset生成的SQL,乍看起来很复杂,经过分析,其实就是通过inner join将两个表的数据连起来。
例如:
表A 表B
id val1 id val2
1 A 1 D
2 B 2 E
3 C 3 F
通过inner join最后会变为横表
id val1 val2
1 A D
2 B E
3 C F
而通过UNION ALL则会变为纵表
id val
1 A
2 B
3 C
1 D
2 E
3 F
http://www.w3school.com.cn/sql/sql_union.asp
http://www.w3school.com.cn/sql/sql_join_inner.asp
INNER JOIN 关键字在表中存在至少一个匹配时返回行。如果 “Persons” 中的行在 “Orders” 中没有匹配,就不会列出这些行。
LEFT JOIN 关键字会从左表 (Persons) 那里返回所有的行,即使在右表 (Orders) 中没有匹配的行。
RIGHT JOIN 关键字会从右表 (Orders) 那里返回所有的行,即使在左表 (Persons) 中没有匹配的行。
superset的源码
https://github.com/apache/incubator-superset/blob/4250e239a2515be91464c1c0502db5b31ac9ee91/superset/connectors/sqla/models.py

阿里巴巴Java开发规约插件安装

Eclipse版插件支持4.2(Juno,JDK1.8+)及以上版本,我们提供自主的Update Site,通过 Help >> Install New Software 然后输入https://p3c.alibaba.com/plugin/eclipse/update 即可看到安装列表。大家可以通过 Help >> Check for Udates 进行插件新版检测。安装完成后打开java代码,右键菜单里就可以找到选项,运行查看代码质量报告。
详细使用说明:https://yq.aliyun.com/articles/224817
github地址:
https://github.com/alibaba/p3c/tree/master/idea-plugin#run-plugin
 
PMD、FindBug、checkstyle、sonar这些代码检查工具的区别?各自的侧重点是什么?
pmd:基于源代码分析,主要面向安全编码规则,如“避免声明同名变量”,包括风格类、类型使用等等,具备一定的数据流分析和路径分析能力。checkstyle:基于源代码,与pmd类似,但更侧重编码的语法风格,分析深度不及pmd。findbugs:基于字节码分析,大量使用数据流分析技术,侧重运行时错误检测,如空指针引用等,分析深度大于前述两个。sonar:定位是代码质量平台,本身不进行代码分析,但可以集成各个静态分析工具以及其他软件开发测试工具,并基于集成工具的结果数据按照一定的质量模型,如iso-9126,对软件的质量进行评估。
https://www.ibm.com/developerworks/cn/java/j-lo-statictest-tools/
使用效果如图: